Ignore:
Timestamp:
Mar 7, 2006, 12:01:59 AM (14 years ago)
Author:
Sam Hocevar
Message:
  • Split caca/graphics.c into driver-specific files. Resize is currently broken, and event handling is not yet in the driver-specific files, but I will of course fix that later.
Location:
libcaca/trunk/caca
Files:
5 edited
6 copied

Legend:

Unmodified
Added
Removed
  • libcaca/trunk/caca/Makefile.am

    r536 r539  
    1212        event.c \
    1313        time.c \
     14        driver_conio.c \
     15        driver_gl.c \
     16        driver_ncurses.c \
     17        driver_slang.c \
     18        driver_win32.c \
     19        driver_x11.c \
    1420        $(NULL)
    1521libcaca_la_CPPFLAGS = -I$(top_srcdir)/cucul
  • libcaca/trunk/caca/caca.c

    r536 r539  
    2929#endif
    3030
    31 #if defined(USE_SLANG)
    32 #   if defined(HAVE_SLANG_SLANG_H)
    33 #       include <slang/slang.h>
    34 #   else
    35 #       include <slang.h>
    36 #   endif
    37 #endif
    38 #if defined(USE_NCURSES)
    39 #   if defined(HAVE_NCURSES_H)
    40 #       include <ncurses.h>
    41 #   else
    42 #       include <curses.h>
    43 #   endif
    44 #endif
    45 #if defined(USE_CONIO)
    46 #   include <dos.h>
    47 #   include <conio.h>
    48 #endif
    49 #if defined(USE_X11)
    50 #   include <X11/Xlib.h>
    51 #endif
    52 #if defined(USE_WIN32)
    53 #   include <windows.h>
    54 #endif
    55 #if defined(USE_GL)
    56 #   include <GL/gl.h>
    57 #endif
    5831#include <stdlib.h>
    5932#include <string.h>
     
    6437#include "caca_internals.h"
    6538
    66 static void caca_init_driver(caca_t *kk);
     39static int caca_init_driver(caca_t *kk);
    6740static void caca_init_terminal(caca_t *kk);
    6841
    69 #if defined(USE_NCURSES)
    70 static mmask_t oldmask;
    71 #endif
    72 
    73 #if defined(USE_WIN32)
    74 static CONSOLE_CURSOR_INFO cci;
    75 #endif
    76 
    7742caca_t * caca_attach(cucul_t * qq)
    7843{
     44    int ret;
    7945    caca_t *kk = malloc(sizeof(caca_t));
    8046
    81 #if defined(USE_NCURSES)
    82     mmask_t newmask;
    83 #endif
    84 
    85     caca_init_driver(kk);
    86 
    87     if(kk->driver == CACA_DRIVER_NONE)
     47    ret = caca_init_driver(kk);
     48
     49    if(ret)
     50    {
     51        free(kk);
    8852        return NULL;
    89 
     53    }
     54
     55    qq->refcount++;
     56    kk->qq = qq;
     57
     58    /* Only for slang and ncurses */
    9059    caca_init_terminal(kk);
    9160
    92 #if defined(USE_SLANG)
    93     if(kk->driver == CACA_DRIVER_SLANG)
    94     {
    95         /* Initialise slang library */
    96         SLsig_block_signals();
    97         SLtt_get_terminfo();
    98 
    99         if(SLkp_init() == -1)
    100         {
    101             SLsig_unblock_signals();
    102             return NULL;
    103         }
    104 
    105         SLang_init_tty(-1, 0, 1);
    106 
    107         if(SLsmg_init_smg() == -1)
    108         {
    109             SLsig_unblock_signals();
    110             return NULL;
    111         }
    112 
    113         SLsig_unblock_signals();
    114 
    115         SLsmg_cls();
    116         SLtt_set_cursor_visibility(0);
    117         SLkp_define_keysym("\e[M", 1001);
    118         SLtt_set_mouse_mode(1, 0);
    119         SLsmg_refresh();
    120 
    121         /* Disable scrolling so that hashmap scrolling optimization code
    122          * does not cause ugly refreshes due to slow terminals */
    123         SLtt_Term_Cannot_Scroll = 1;
    124     }
    125     else
    126 #endif
    127 #if defined(USE_NCURSES)
    128     if(kk->driver == CACA_DRIVER_NCURSES)
    129     {
    130         initscr();
    131         keypad(stdscr, TRUE);
    132         nonl();
    133         raw();
    134         noecho();
    135         nodelay(stdscr, TRUE);
    136         curs_set(0);
    137 
    138         /* Activate mouse */
    139         newmask = REPORT_MOUSE_POSITION | ALL_MOUSE_EVENTS;
    140         mousemask(newmask, &oldmask);
    141         mouseinterval(-1); /* No click emulation */
    142 
    143         /* Set the escape delay to a ridiculously low value */
    144         ESCDELAY = 10;
    145     }
    146     else
    147 #endif
    148 #if defined(USE_CONIO)
    149     if(kk->driver == CACA_DRIVER_CONIO)
    150     {
    151         _wscroll = 0;
    152         _setcursortype(_NOCURSOR);
    153         clrscr();
    154     }
    155     else
    156 #endif
    157 #if defined(USE_X11)
    158     if(kk->driver == CACA_DRIVER_X11)
    159     {
    160         /* Nothing to do */
    161         kk->x11.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask
    162               | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask
    163               | ExposureMask;
    164     }
    165     else
    166 #endif
    167 #if defined(USE_WIN32)
    168     if(kk->driver == CACA_DRIVER_WIN32)
    169     {
    170         /* This call is allowed to fail in case we already have a console */
    171         AllocConsole();
    172 
    173         kk->win32.hin = GetStdHandle(STD_INPUT_HANDLE);
    174         kk->win32.hout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
    175                                     FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
    176                                     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    177 
    178         if(kk->win32.hout == INVALID_HANDLE_VALUE)
    179             return NULL;
    180 
    181         GetConsoleCursorInfo(kk->win32.hout, &cci);
    182         cci.bVisible = FALSE;
    183         SetConsoleCursorInfo(kk->win32.hout, &cci);
    184 
    185         SetConsoleMode(kk->win32.hout, ENABLE_MOUSE_INPUT);
    186     }
    187     else
    188 #endif
    189 #if defined(USE_GL)
    190     if(kk->driver == CACA_DRIVER_GL)
    191     {
    192         /* Nothing to do */
    193     }
    194     else
    195 #endif
    196     {
    197         /* Dummy */
     61    if(_caca_init_graphics(kk))
     62    {
     63        qq->refcount--;
     64        free(kk);
     65        return NULL;
    19866    }
    19967
     
    20573    kk->events.last_key = 0;
    20674
    207     qq->refcount++;
    208     kk->qq = qq;
    209 
    21075    kk->timer.last_sec = 0;
    21176    kk->timer.last_usec = 0;
     
    21580    kk->resize_event = 0;
    21681
    217     if(_caca_init_graphics(kk))
    218         return NULL;
    219 
    22082    return kk;
    22183}
     
    22385void caca_detach(caca_t *kk)
    22486{
    225     _caca_end_graphics(kk);
    226 
    227 #if defined(USE_SLANG)
    228     if(kk->driver == CACA_DRIVER_SLANG)
    229     {
    230         SLtt_set_mouse_mode(0, 0);
    231         SLtt_set_cursor_visibility(1);
    232         SLang_reset_tty();
    233         SLsmg_reset_smg();
    234     }
    235     else
    236 #endif
    237 #if defined(USE_NCURSES)
    238     if(kk->driver == CACA_DRIVER_NCURSES)
    239     {
    240         mousemask(oldmask, NULL);
    241         curs_set(1);
    242         noraw();
    243         endwin();
    244     }
    245     else
    246 #endif
    247 #if defined(USE_CONIO)
    248     if(kk->driver == CACA_DRIVER_CONIO)
    249     {
    250         _wscroll = 1;
    251         textcolor((enum COLORS)WHITE);
    252         textbackground((enum COLORS)BLACK);
    253         gotoxy(_caca_width, _caca_height);
    254         cputs("\r\n");
    255         _setcursortype(_NORMALCURSOR);
    256     }
    257     else
    258 #endif
    259 #if defined(USE_X11)
    260     if(kk->driver == CACA_DRIVER_X11)
    261     {
    262         /* Nothing to do */
    263     }
    264     else
    265 #endif
    266 #if defined(USE_WIN32)
    267     if(kk->driver == CACA_DRIVER_WIN32)
    268     {
    269         SetConsoleTextAttribute(kk->win32.hout, FOREGROUND_INTENSITY
    270                                                  | FOREGROUND_RED
    271                                                  | FOREGROUND_GREEN
    272                                                  | FOREGROUND_BLUE);
    273         cci.bVisible = TRUE;
    274         SetConsoleCursorInfo(kk->win32.hout, &cci);
    275         CloseHandle(kk->win32.hout);
    276     }
    277     else
    278 #endif
    279 #if defined(USE_GL)
    280     if(kk->driver == CACA_DRIVER_GL)
    281     {
    282         /* Nothing to do */
    283     }
    284     else
    285 #endif
    286     {
    287         /* Dummy */
    288     }
    289 
     87    kk->driver.end_graphics(kk);
    29088    kk->qq->refcount--;
    291 
    29289    free(kk);
    29390}
     
    29794 */
    29895
    299 static void caca_init_driver(caca_t *kk)
     96static int caca_init_driver(caca_t *kk)
    30097{
    30198#if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP)
     
    307104#if defined(USE_WIN32)
    308105        if(!strcasecmp(var, "win32"))
    309             kk->driver = CACA_DRIVER_WIN32;
     106            win32_init_driver(kk);
    310107        else
    311108#endif
    312109#if defined(USE_CONIO)
    313110        if(!strcasecmp(var, "conio"))
    314             kk->driver = CACA_DRIVER_CONIO;
     111            conio_init_driver(kk);
    315112        else
    316113#endif
    317114#if defined(USE_X11)
    318115        if(!strcasecmp(var, "x11"))
    319             kk->driver = CACA_DRIVER_X11;
     116            x11_init_driver(kk);
    320117        else
    321118#endif
    322119#if defined(USE_GL)
    323120        if(!strcasecmp(var, "gl"))
    324             kk->driver = CACA_DRIVER_GL;
     121            gl_init_driver(kk);
    325122        else
    326123#endif
    327124#if defined(USE_SLANG)
    328125        if(!strcasecmp(var, "slang"))
    329             kk->driver = CACA_DRIVER_SLANG;
     126            slang_init_driver(kk);
    330127        else
    331128#endif
    332129#if defined(USE_NCURSES)
    333130        if(!strcasecmp(var, "ncurses"))
    334             kk->driver = CACA_DRIVER_NCURSES;
    335         else
    336 #endif
    337 
    338             kk->driver = CACA_DRIVER_NONE;
    339 
    340         return;
     131            ncurses_init_driver(kk);
     132        else
     133#endif
     134            return -1;
     135
     136        return 0;
    341137    }
    342138#endif
    343139
    344140#if defined(USE_WIN32)
    345     kk->driver = CACA_DRIVER_WIN32;
    346     return;
     141    win32_init_driver(kk);
     142    return 0;
    347143#endif
    348144#if defined(USE_CONIO)
    349     kk->driver = CACA_DRIVER_CONIO;
    350     return;
     145    conio_init_driver(kk);
     146    return 0;
    351147#endif
    352148#if defined(USE_X11)
     
    355151#endif
    356152    {
    357         kk->driver = CACA_DRIVER_X11;
    358         return;
     153        x11_init_driver(kk);
     154        return 0;
    359155    }
    360156#endif
     
    364160#endif
    365161    {
    366         kk->driver = CACA_DRIVER_GL;
    367         return;
     162        gl_init_driver(kk);
     163        return 0;
    368164    }
    369165#endif
    370166#if defined(USE_SLANG)
    371     kk->driver = CACA_DRIVER_SLANG;
    372     return;
    373 #endif
    374 #if defined(USE_NCURSES)
    375     kk->driver = CACA_DRIVER_NCURSES;
    376     return;
    377 #endif
    378 
    379     kk->driver = CACA_DRIVER_NONE;
    380     return;
     167    slang_init_driver(kk);
     168    return 0;
     169#endif
     170#if defined(USE_NCURSES)
     171    slang_init_driver(kk);
     172    return 0;
     173#endif
     174
     175    return -1;
    381176}
    382177
     
    389184
    390185#if defined(USE_SLANG)
    391     if(kk->driver != CACA_DRIVER_SLANG)
    392 #endif
    393 #if defined(USE_NCURSES)
    394     if(kk->driver != CACA_DRIVER_NCURSES)
     186    if(kk->driver.driver != CACA_DRIVER_SLANG)
     187#endif
     188#if defined(USE_NCURSES)
     189    if(kk->driver.driver != CACA_DRIVER_NCURSES)
    395190#endif
    396191    return;
     
    407202        {
    408203#if defined(USE_NCURSES)
    409             if(kk->driver == CACA_DRIVER_NCURSES)
     204            if(kk->driver.driver == CACA_DRIVER_NCURSES)
    410205            {
    411206                SCREEN *screen;
     
    425220        {
    426221#if defined(USE_NCURSES)
    427             if(kk->driver == CACA_DRIVER_NCURSES)
     222            if(kk->driver.driver == CACA_DRIVER_NCURSES)
    428223            {
    429224                SCREEN *screen;
  • libcaca/trunk/caca/caca_internals.h

    r536 r539  
    2121#define __CACA_INTERNALS_H__
    2222
     23#if defined(USE_GL)
     24#   include <GL/glut.h>
     25#endif
     26#if defined(USE_NCURSES)
     27#   if defined(HAVE_NCURSES_H)
     28#       include <ncurses.h>
     29#   else
     30#       include <curses.h>
     31#   endif
     32#endif
     33#if defined(USE_WIN32)
     34#   include <windows.h>
     35#endif
    2336#if defined(USE_X11)
    24 #include <X11/Xlib.h>
     37#   include <X11/Xlib.h>
    2538#endif
    2639
     
    4962};
    5063
     64/* Available drivers */
     65#if defined(USE_CONIO)
     66void conio_init_driver(caca_t *);
     67#endif
     68#if defined(USE_GL)
     69void gl_init_driver(caca_t *);
     70#endif
     71#if defined(USE_NCURSES)
     72void ncurses_init_driver(caca_t *);
     73#endif
     74#if defined(USE_SLANG)
     75void slang_init_driver(caca_t *);
     76#endif
     77#if defined(USE_WIN32)
     78void win32_init_driver(caca_t *);
     79#endif
     80#if defined(USE_X11)
     81void x11_init_driver(caca_t *);
     82#endif
     83
    5184/* Timer structure */
    5285struct caca_timer
     
    6093    cucul_t *qq;
    6194
    62     enum caca_driver driver;
     95    struct driver
     96    {
     97        enum caca_driver driver;
     98
     99        int (* init_graphics) (caca_t *);
     100        int (* end_graphics) (caca_t *);
     101        int (* set_window_title) (caca_t *, char const *);
     102        unsigned int (* get_window_width) (caca_t *);
     103        unsigned int (* get_window_height) (caca_t *);
     104        void (* display) (caca_t *);
     105        void (* handle_resize) (caca_t *);
     106    } driver;
     107
    63108    unsigned int width, height;
    64109
     
    103148    {
    104149        int attr[16*16];
     150        mmask_t oldmask;
    105151    } ncurses;
    106152#endif
     
    157203extern int _caca_resize_event;
    158204
    159 #if defined(USE_WIN32)
    160 #include <windows.h>
    161 extern HANDLE win32_hin, win32_hout;
    162 #endif
    163 
    164 #if defined(USE_GL)
    165 #include <GL/glut.h>
    166 extern unsigned int gl_width, gl_height;
    167 #endif
    168 
    169 
    170205#endif /* __CACA_INTERNALS_H__ */
  • libcaca/trunk/caca/driver_conio.c

    r537 r539  
    2020#include "config.h"
    2121
    22 #if defined(USE_SLANG)
    23 #   if defined(HAVE_SLANG_SLANG_H)
    24 #       include <slang/slang.h>
    25 #   else
    26 #       include <slang.h>
    27 #   endif
    28 #endif
    29 #if defined(USE_NCURSES)
    30 #   if defined(HAVE_NCURSES_H)
    31 #       include <ncurses.h>
    32 #   else
    33 #       include <curses.h>
    34 #   endif
    35 #endif
    36 #if defined(USE_CONIO)
    37 #   include <conio.h>
    38 #   if defined(SCREENUPDATE_IN_PC_H)
    39 #       include <pc.h>
    40 #   endif
    41 #endif
    42 #if defined(USE_X11)
    43 #   include <X11/Xlib.h>
    44 #   if defined(HAVE_X11_XKBLIB_H)
    45 #       include <X11/XKBlib.h>
    46 #   endif
    47 #endif
    48 #if defined(USE_WIN32)
    49 #   include <windows.h>
    50 #endif
    51 #if defined(USE_GL)
    52 #   include <GL/gl.h>
    53 #   include <GL/glut.h>
    54 #   include <GL/freeglut_ext.h>
    55 #endif
    5622#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME)
    5723#   include <inttypes.h>
     
    6127#endif
    6228
    63 #include <stdio.h> /* BUFSIZ */
     29#if defined(USE_CONIO)
     30
     31#include <dos.h>
     32#include <conio.h>
     33#if defined(SCREENUPDATE_IN_PC_H)
     34#   include <pc.h>
     35#endif
     36
    6437#include <string.h>
    6538#include <stdlib.h>
     
    6942#include <stdarg.h>
    7043
    71 #if defined(HAVE_SIGNAL_H)
    72 #   include <signal.h>
    73 #endif
    7444#if defined(HAVE_SYS_IOCTL_H)
    7545#   include <sys/ioctl.h>
     
    8151#include "cucul_internals.h"
    8252
    83 /*
    84  * Global variables
    85  */
     53#if !defined(_DOXYGEN_SKIP_ME)
     54int conio_init_graphics(caca_t *kk)
     55{
     56    _wscroll = 0;
     57    _setcursortype(_NOCURSOR);
     58    clrscr();
    8659
    87 #if defined(USE_SLANG)
    88 /* Tables generated by test/optipal.c */
    89 static int const slang_palette[2*16*16] =
    90 {
    91      1,  0,   2,  0,   3,  0,   4,  0,   5,  0,   6,  0,   7,  0,   8,  0,
    92      9,  0,  10,  0,  11,  0,  12,  0,  13,  0,  14,  0,  15,  0,   0,  8,
    93      8,  7,   7,  8,  15,  7,   7, 15,  15,  9,   9, 15,   1,  9,   9,  1,
    94      7,  9,   9,  7,   8,  1,   1,  8,   0,  1,  15, 10,  10, 15,   2, 10,
    95     10,  2,   7, 10,  10,  7,   8,  2,   2,  8,   0,  2,  15, 11,  11, 15,
    96      3, 11,  11,  3,   7, 11,  11,  7,   8,  3,   3,  8,   0,  3,  15, 12,
    97     12, 15,   4, 12,  12,  4,   7, 12,  12,  7,   8,  4,   4,  8,   0,  4,
    98     15, 13,  13, 15,   5, 13,  13,  5,   7, 13,  13,  7,   8,  5,   5,  8,
    99      0,  5,  15, 14,  14, 15,   6, 14,  14,  6,   7, 14,  14,  7,   8,  6,
    100      6,  8,   0,  6,   4,  6,   6,  4,  12, 14,  14, 12,   6,  2,   2,  6,
    101     14, 10,  10, 14,   2,  3,   3,  2,  10, 11,  11, 10,   3,  1,   1,  3,
    102     11,  9,   9, 11,   1,  5,   5,  1,   9, 13,  13,  9,   5,  4,   4,  5,
    103     13, 12,  12, 13,   4, 14,   6, 12,  12,  6,  14,  4,   6, 10,   2, 14,
    104     14,  2,  10,  6,   2, 11,   3, 10,  10,  3,  11,  2,   3,  9,   1, 11,
    105     11,  1,   9,  3,   1, 13,   5,  9,   9,  5,  13,  1,   5, 12,   4, 13,
    106     13,  4,  12,  5,   0,  7,   0, 15,  15,  8,   8, 15,  15,  1,   7,  1,
    107      1,  6,   2,  5,   3,  4,   4,  3,   5,  2,   6,  1,   0,  0,   1,  1,
    108      9,  6,  10,  5,  11,  4,  12,  3,  13,  2,  14,  1,   2,  2,   3,  3,
    109      4,  4,   5,  5,   6,  6,   7,  7,  14,  9,   1, 15,   8,  9,   8,  8,
    110      9,  9,   1,  7,   0,  9,   9,  8,   6,  9,  13, 10,   2, 15,   8, 10,
    111      7,  2,  15,  2,   2,  7,   0, 10,  10,  8,   5, 10,  12, 11,   3, 15,
    112      8, 11,   7,  3,  15,  3,   3,  7,   0, 11,  11,  8,   4, 11,  11, 12,
    113      4, 15,   8, 12,   7,  4,  15,  4,   4,  7,   0, 12,  12,  8,   3, 12,
    114     10, 13,   5, 15,   8, 13,   7,  5,  15,  5,   5,  7,   0, 13,  13,  8,
    115      2, 13,   9, 14,   6, 15,   8, 14,   7,  6,  15,  6,   6,  7,   0, 14,
    116     14,  8,   1, 14,   5,  6,   2,  4,  13, 14,  10, 12,   4,  2,   3,  6,
    117     12, 10,  11, 14,   6,  3,   1,  2,  14, 11,   9, 10,   2,  1,   5,  3,
    118     10,  9,  13, 11,   3,  5,   4,  1,  11, 13,  12,  9,   1,  4,   6,  5,
    119      9, 12,  14, 13,   5, 14,   2, 12,  13,  6,  10,  4,   4, 10,   3, 14,
    120     12,  2,  11,  6,   6, 11,   1, 10,  14,  3,   9,  2,   2,  9,   5, 11,
    121     10,  1,  13,  3,   3, 13,   4,  9,  11,  5,  12,  1,   1, 12,   6, 13,
    122      9,  4,  14,  5,  10, 10,  11, 11,  12, 12,  13, 13,  14, 14,  15, 15,
    123 };
    124 
    125 static int const slang_assoc[16*16] =
    126 {
    127     134, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
    128     28, 135, 214, 86, 219, 91, 133, 127, 26, 23, 240, 112, 245, 117, 141, 126,
    129     37, 211, 142, 83, 206, 132, 78, 160, 35, 237, 32, 109, 232, 140, 104, 161,
    130     46, 87, 82, 143, 131, 215, 210, 169, 44, 113, 108, 41, 139, 241, 236, 170,
    131     55, 222, 203, 130, 144, 94, 75, 178, 53, 248, 229, 138, 50, 120, 101, 179,
    132     64, 90, 129, 218, 95, 145, 223, 187, 62, 116, 137, 244, 121, 59, 249, 188,
    133     73, 128, 79, 207, 74, 202, 146, 196, 71, 136, 105, 233, 100, 228, 68, 197,
    134     122, 153, 162, 171, 180, 189, 198, 147, 16, 25, 34, 43, 52, 61, 70, 18,
    135     15, 27, 36, 45, 54, 63, 72, 17, 151, 155, 164, 173, 182, 191, 200, 124,
    136     154, 22, 238, 110, 243, 115, 156, 24, 150, 152, 216, 88, 221, 93, 148, 20,
    137     163, 235, 31, 107, 230, 165, 102, 33, 159, 213, 250, 85, 208, 157, 80, 29,
    138     172, 111, 106, 40, 174, 239, 234, 42, 168, 89, 84, 251, 166, 217, 212, 38,
    139     181, 246, 227, 183, 49, 118, 99, 51, 177, 224, 205, 175, 252, 96, 77, 47,
    140     190, 114, 192, 242, 119, 58, 247, 60, 186, 92, 184, 220, 97, 253, 225, 56,
    141     199, 201, 103, 231, 98, 226, 67, 69, 195, 193, 81, 209, 76, 204, 254, 65,
    142     123, 149, 158, 167, 176, 185, 194, 19, 125, 21, 30, 39, 48, 57, 66, 255,
    143 };
    144 #endif
    145 
    146 #if defined(USE_WIN32)
    147 static int const win32_fg_palette[] =
    148 {
    149     0,
    150     FOREGROUND_BLUE,
    151     FOREGROUND_GREEN,
    152     FOREGROUND_GREEN | FOREGROUND_BLUE,
    153     FOREGROUND_RED,
    154     FOREGROUND_RED | FOREGROUND_BLUE,
    155     FOREGROUND_RED | FOREGROUND_GREEN,
    156     FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
    157     FOREGROUND_INTENSITY,
    158     FOREGROUND_INTENSITY | FOREGROUND_BLUE,
    159     FOREGROUND_INTENSITY | FOREGROUND_GREEN,
    160     FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE,
    161     FOREGROUND_INTENSITY | FOREGROUND_RED,
    162     FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE,
    163     FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN,
    164     FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
    165 };
    166 
    167 static int const win32_bg_palette[] =
    168 {
    169     0,
    170     BACKGROUND_BLUE,
    171     BACKGROUND_GREEN,
    172     BACKGROUND_GREEN | BACKGROUND_BLUE,
    173     BACKGROUND_RED,
    174     BACKGROUND_RED | BACKGROUND_BLUE,
    175     BACKGROUND_RED | BACKGROUND_GREEN,
    176     BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
    177     BACKGROUND_INTENSITY,
    178     BACKGROUND_INTENSITY | BACKGROUND_BLUE,
    179     BACKGROUND_INTENSITY | BACKGROUND_GREEN,
    180     BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE,
    181     BACKGROUND_INTENSITY | BACKGROUND_RED,
    182     BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE,
    183     BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN,
    184     BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
    185 };
    186 #endif
    187 
    188 #if defined(USE_GL)
    189 /* Ok, I just suck. */
    190 static GLbyte const gl_bgpal[][4] =
    191 {
    192     { 0x00, 0x00, 0x00, 0x7f },
    193     { 0x00, 0x00, 0x3f, 0x7f },
    194     { 0x00, 0x3f, 0x00, 0x7f },
    195     { 0x00, 0x3f, 0x3f, 0x7f },
    196     { 0x3f, 0x00, 0x00, 0x7f },
    197     { 0x3f, 0x00, 0x3f, 0x7f },
    198     { 0x3f, 0x3f, 0x00, 0x7f },
    199     { 0x3f, 0x3f, 0x3f, 0x7f },
    200     // + intensity
    201     { 0x00, 0x00, 0x00, 0x7f },
    202     { 0x00, 0x00, 0x7f, 0x7f },
    203     { 0x00, 0x7f, 0x00, 0x7f },
    204     { 0x00, 0x7f, 0x7f, 0x7f },
    205     { 0x7f, 0x00, 0x00, 0x7f },
    206     { 0x7f, 0x00, 0x7f, 0x7f },
    207     { 0x7f, 0x7f, 0x00, 0x7f },
    208     { 0x7f, 0x7f, 0x7f, 0x7f }
    209 };
    210 
    211 static caca_t *gl_kk; /* FIXME: we ought to get rid of this */
    212 #endif
    213 
    214 /*
    215  * Local functions
    216  */
    217 static void caca_handle_resize(caca_t *kk);
    218 
    219 #if defined(USE_SLANG)
    220 static void slang_init_palette(void);
    221 #endif
    222 
    223 #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
    224 static RETSIGTYPE sigwinch_handler(int);
    225 static caca_t *sigwinch_kk; /* FIXME: we ought to get rid of this */
    226 #endif
    227 
    228 #if defined(USE_X11)
    229 static int x11_error_handler(Display *, XErrorEvent *);
    230 #endif
    231 
    232 #if defined(USE_GL)
    233 static void gl_handle_keyboard(unsigned char, int, int);
    234 static void gl_handle_special_key(int, int, int);
    235 static void gl_handle_reshape(int, int);
    236 static void gl_handle_mouse(int, int, int, int);
    237 static void gl_handle_mouse_motion(int, int);
    238 #endif
    239 
    240 #if !defined(_DOXYGEN_SKIP_ME)
    241 int _caca_init_graphics(caca_t *kk)
    242 {
    243 #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
    244     sigwinch_kk = kk;
    245     signal(SIGWINCH, sigwinch_handler);
    246 #endif
    247 
    248 #if defined(USE_SLANG)
    249     if(kk->driver == CACA_DRIVER_SLANG)
    250     {
    251         slang_init_palette();
    252 
    253         /* Disable alt charset support so that we get a chance to have all
    254          * 256 colour pairs */
    255         SLtt_Has_Alt_Charset = 0;
    256 
    257         cucul_set_size(kk->qq, SLtt_Screen_Cols, SLtt_Screen_Rows);
    258     }
    259     else
    260 #endif
    261 #if defined(USE_NCURSES)
    262     if(kk->driver == CACA_DRIVER_NCURSES)
    263     {
    264         static int curses_colors[] =
    265         {
    266             /* Standard curses colours */
    267             COLOR_BLACK,
    268             COLOR_BLUE,
    269             COLOR_GREEN,
    270             COLOR_CYAN,
    271             COLOR_RED,
    272             COLOR_MAGENTA,
    273             COLOR_YELLOW,
    274             COLOR_WHITE,
    275             /* Extra values for xterm-16color */
    276             COLOR_BLACK + 8,
    277             COLOR_BLUE + 8,
    278             COLOR_GREEN + 8,
    279             COLOR_CYAN + 8,
    280             COLOR_RED + 8,
    281             COLOR_MAGENTA + 8,
    282             COLOR_YELLOW + 8,
    283             COLOR_WHITE + 8
    284         };
    285 
    286         int fg, bg, max;
    287 
    288         /* Activate colour */
    289         start_color();
    290 
    291         /* If COLORS == 16, it means the terminal supports full bright colours
    292          * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
    293          * we can build 16*16 colour pairs.
    294          * If COLORS == 8, it means the terminal does not know about bright
    295          * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
    296          * and \e[5m). We can only build 8*8 colour pairs. */
    297         max = COLORS >= 16 ? 16 : 8;
    298 
    299         for(bg = 0; bg < max; bg++)
    300             for(fg = 0; fg < max; fg++)
    301             {
    302                 /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
    303                  * is light gray on black. Some terminals don't like this
    304                  * colour pair to be redefined. */
    305                 int col = ((max + 7 - fg) % max) + max * bg;
    306                 init_pair(col, curses_colors[fg], curses_colors[bg]);
    307                 kk->ncurses.attr[fg + 16 * bg] = COLOR_PAIR(col);
    308 
    309                 if(max == 8)
    310                 {
    311                     /* Bright fg on simple bg */
    312                     kk->ncurses.attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
    313                     /* Simple fg on bright bg */
    314                     kk->ncurses.attr[fg + 16 * (bg + 8)] = A_BLINK
    315                                                         | COLOR_PAIR(col);
    316                     /* Bright fg on bright bg */
    317                     kk->ncurses.attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
    318                                                             | COLOR_PAIR(col);
    319                 }
    320             }
    321 
    322         cucul_set_size(kk->qq, COLS, LINES);
    323     }
    324     else
    325 #endif
    326 #if defined(USE_CONIO)
    327     if(kk->driver == CACA_DRIVER_CONIO)
    328     {
    329         gettextinfo(&kk->conio.ti);
    330         kk->conio.screen = malloc(2 * kk->conio.ti.screenwidth
     60    gettextinfo(&kk->conio.ti);
     61    kk->conio.screen = malloc(2 * kk->conio.ti.screenwidth
    33162                                * kk->conio.ti.screenheight * sizeof(char));
    332         if(kk->conio.screen == NULL)
    333             return -1;
     63    if(kk->conio.screen == NULL)
     64        return -1;
    33465#   if defined(SCREENUPDATE_IN_PC_H)
    335         ScreenRetrieve(kk->conio.screen);
     66    ScreenRetrieve(kk->conio.screen);
    33667#   else
    337         /* FIXME */
     68    /* FIXME */
    33869#   endif
    339         cucul_set_size(kk->qq, kk->conio.ti.screenwidth,
    340                                kk->conio.ti.screenheight);
    341     }
    342     else
    343 #endif
    344 #if defined(USE_X11)
    345     if(kk->driver == CACA_DRIVER_X11)
    346     {
    347         static int const x11_palette[] =
    348         {
    349             /* Standard curses colours */
    350             0x0,    0x0,    0x0,
    351             0x0,    0x0,    0x8000,
    352             0x0,    0x8000, 0x0,
    353             0x0,    0x8000, 0x8000,
    354             0x8000, 0x0,    0x0,
    355             0x8000, 0x0,    0x8000,
    356             0x8000, 0x8000, 0x0,
    357             0x8000, 0x8000, 0x8000,
    358             /* Extra values for xterm-16color */
    359             0x4000, 0x4000, 0x4000,
    360             0x4000, 0x4000, 0xffff,
    361             0x4000, 0xffff, 0x4000,
    362             0x4000, 0xffff, 0xffff,
    363             0xffff, 0x4000, 0x4000,
    364             0xffff, 0x4000, 0xffff,
    365             0xffff, 0xffff, 0x4000,
    366             0xffff, 0xffff, 0xffff,
    367         };
    368 
    369         Colormap colormap;
    370         XSetWindowAttributes x11_winattr;
    371         int (*old_error_handler)(Display *, XErrorEvent *);
    372         char const *fonts[] = { NULL, "8x13bold", "fixed" }, **parser;
    373         char const *geometry;
    374         unsigned int width = 0, height = 0;
    375         int i;
    376 
    377         geometry = getenv("CACA_GEOMETRY");
    378         if(geometry && *(geometry))
    379             sscanf(geometry, "%ux%u", &width, &height);
    380 
    381         if(width && height)
    382             cucul_set_size(kk->qq, width, height);
    383 
    384         kk->x11.dpy = XOpenDisplay(NULL);
    385         if(kk->x11.dpy == NULL)
    386             return -1;
    387 
    388         fonts[0] = getenv("CACA_FONT");
    389         if(fonts[0] && *fonts[0])
    390             parser = fonts;
    391         else
    392             parser = fonts + 1;
    393 
    394         /* Ignore font errors */
    395         old_error_handler = XSetErrorHandler(x11_error_handler);
    396 
    397         /* Parse our font list */
    398         for( ; ; parser++)
    399         {
    400             if(!*parser)
    401             {
    402                 XSetErrorHandler(old_error_handler);
    403                 XCloseDisplay(kk->x11.dpy);
    404                 return -1;
    405             }
    406 
    407             kk->x11.font = XLoadFont(kk->x11.dpy, *parser);
    408             if(!kk->x11.font)
    409                 continue;
    410 
    411             kk->x11.font_struct = XQueryFont(kk->x11.dpy, kk->x11.font);
    412             if(!kk->x11.font_struct)
    413             {
    414                 XUnloadFont(kk->x11.dpy, kk->x11.font);
    415                 continue;
    416             }
    417 
    418             break;
    419         }
    420 
    421         /* Reset the default X11 error handler */
    422         XSetErrorHandler(old_error_handler);
    423 
    424         kk->x11.font_width = kk->x11.font_struct->max_bounds.width;
    425         kk->x11.font_height = kk->x11.font_struct->max_bounds.ascent
    426                              + kk->x11.font_struct->max_bounds.descent;
    427         kk->x11.font_offset = kk->x11.font_struct->max_bounds.descent;
    428 
    429         colormap = DefaultColormap(kk->x11.dpy, DefaultScreen(kk->x11.dpy));
    430         for(i = 0; i < 16; i++)
    431         {
    432             XColor color;
    433             color.red = x11_palette[i * 3];
    434             color.green = x11_palette[i * 3 + 1];
    435             color.blue = x11_palette[i * 3 + 2];
    436             XAllocColor(kk->x11.dpy, colormap, &color);
    437             kk->x11.colors[i] = color.pixel;
    438         }
    439 
    440         x11_winattr.backing_store = Always;
    441         x11_winattr.background_pixel = kk->x11.colors[0];
    442         x11_winattr.event_mask = ExposureMask | StructureNotifyMask;
    443 
    444         kk->x11.window =
    445             XCreateWindow(kk->x11.dpy, DefaultRootWindow(kk->x11.dpy), 0, 0,
    446                           kk->qq->width * kk->x11.font_width,
    447                           kk->qq->height * kk->x11.font_height,
    448                           0, 0, InputOutput, 0,
    449                           CWBackingStore | CWBackPixel | CWEventMask,
    450                           &x11_winattr);
    451 
    452         XStoreName(kk->x11.dpy, kk->x11.window, "caca for X");
    453 
    454         XSelectInput(kk->x11.dpy, kk->x11.window, StructureNotifyMask);
    455         XMapWindow(kk->x11.dpy, kk->x11.window);
    456 
    457         kk->x11.gc = XCreateGC(kk->x11.dpy, kk->x11.window, 0, NULL);
    458         XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[15]);
    459         XSetFont(kk->x11.dpy, kk->x11.gc, kk->x11.font);
    460 
    461         for(;;)
    462         {
    463             XEvent event;
    464             XNextEvent(kk->x11.dpy, &event);
    465             if (event.type == MapNotify)
    466                 break;
    467         }
    468 
    469 #if defined(HAVE_X11_XKBLIB_H)
    470         /* Disable autorepeat */
    471         XkbSetDetectableAutoRepeat(kk->x11.dpy, True, &kk->x11.autorepeat);
    472         if(!kk->x11.autorepeat)
    473             XAutoRepeatOff(kk->x11.dpy);
    474 #endif
    475 
    476         XSelectInput(kk->x11.dpy, kk->x11.window, kk->x11.event_mask);
    477 
    478         XSync(kk->x11.dpy, False);
    479 
    480         kk->x11.pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window,
    481                                        kk->qq->width * kk->x11.font_width,
    482                                        kk->qq->height * kk->x11.font_height,
    483                                        DefaultDepth(kk->x11.dpy,
    484                                                 DefaultScreen(kk->x11.dpy)));
    485 
    486         kk->x11.new_width = kk->x11.new_height = 0;
    487     }
    488     else
    489 #endif
    490 #if defined(USE_WIN32)
    491     if(kk->driver == CACA_DRIVER_WIN32)
    492     {
    493         CONSOLE_CURSOR_INFO cci;
    494         CONSOLE_SCREEN_BUFFER_INFO csbi;
    495         COORD size;
    496 
    497         kk->win32.front =
    498             CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
    499                                       0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    500         if(!kk->win32.front || kk->win32.front == INVALID_HANDLE_VALUE)
    501             return -1;
    502 
    503         kk->win32.back =
    504             CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
    505                                       0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    506         if(!kk->win32.back || kk->win32.back == INVALID_HANDLE_VALUE)
    507             return -1;
    508 
    509         if(!GetConsoleScreenBufferInfo(kk->win32.hout, &csbi))
    510             return -1;
    511 
    512         /* Sample code to get the biggest possible window */
    513         //size = GetLargestConsoleWindowSize(kk->win32.hout);
    514         cucul_set_size(kk->qq, csbi.srWindow.Right - csbi.srWindow.Left + 1,
    515                                csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
    516         size.X = kk->qq->width;
    517         size.Y = kk->qq->height;
    518         SetConsoleScreenBufferSize(kk->win32.front, size);
    519         SetConsoleScreenBufferSize(kk->win32.back, size);
    520 
    521         SetConsoleMode(kk->win32.front, 0);
    522         SetConsoleMode(kk->win32.back, 0);
    523 
    524         GetConsoleCursorInfo(kk->win32.front, &cci);
    525         cci.dwSize = 0;
    526         cci.bVisible = FALSE;
    527         SetConsoleCursorInfo(kk->win32.front, &cci);
    528         SetConsoleCursorInfo(kk->win32.back, &cci);
    529 
    530         SetConsoleActiveScreenBuffer(kk->win32.front);
    531 
    532         kk->win32.buffer = malloc(kk->qq->width * kk->qq->height
    533                                    * sizeof(CHAR_INFO));
    534         if(kk->win32.buffer == NULL)
    535             return -1;
    536     }
    537     else
    538 #endif
    539 #if defined(USE_GL)
    540     if(kk->driver == CACA_DRIVER_GL)
    541     {
    542         char *empty_texture;
    543         char const *geometry;
    544         char *argv[2] = { "", NULL };
    545         unsigned int width = 0, height = 0;
    546         int argc = 1;
    547         int i;
    548 
    549         gl_kk = kk;
    550 
    551         geometry = getenv("CACA_GEOMETRY");
    552         if(geometry && *(geometry))
    553             sscanf(geometry, "%ux%u", &width, &height);
    554 
    555         if(width && height)
    556             cucul_set_size(kk->qq, width, height);
    557 
    558         kk->gl.font_width = 9;
    559         kk->gl.font_height = 15;
    560 
    561         kk->gl.width = kk->qq->width * kk->gl.font_width;
    562         kk->gl.height = kk->qq->height * kk->gl.font_height;
    563 
    564         kk->gl.resized = 0;
    565         kk->gl.bit = 0;
    566 
    567         kk->gl.mouse_changed = kk->gl.mouse_clicked = 0;
    568         kk->gl.mouse_button = kk->gl.mouse_state = 0;
    569 
    570         kk->gl.key = 0;
    571         kk->gl.special_key = 0;
    572 
    573         kk->gl.sw = 9.0f / 16.0f;
    574         kk->gl.sh = 15.0f / 16.0f;
    575 
    576         glutInit(&argc, argv);
    577 
    578         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    579         glutInitWindowSize(kk->gl.width, kk->gl.height);
    580         kk->gl.window = glutCreateWindow("caca for GL");
    581 
    582         gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
    583 
    584         glDisable(GL_CULL_FACE);
    585         glDisable(GL_DEPTH_TEST);
    586 
    587         glutKeyboardFunc(gl_handle_keyboard);
    588         glutSpecialFunc(gl_handle_special_key);
    589         glutReshapeFunc(gl_handle_reshape);
    590 
    591         glutMouseFunc(gl_handle_mouse);
    592         glutMotionFunc(gl_handle_mouse_motion);
    593         glutPassiveMotionFunc(gl_handle_mouse_motion);
    594 
    595         glLoadIdentity();
    596 
    597         glMatrixMode(GL_PROJECTION);
    598         glPushMatrix();
    599         glLoadIdentity();
    600         gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
    601 
    602         glMatrixMode(GL_MODELVIEW);
    603 
    604         glClear(GL_COLOR_BUFFER_BIT);
    605 
    606         empty_texture = malloc(16 * 16 * 4);
    607         if(empty_texture == NULL)
    608             return -1;
    609 
    610         memset(empty_texture, 0xff, 16 * 16 * 4);
    611         glEnable(GL_TEXTURE_2D);
    612 
    613         for(i = 0; i < 94; i++)
    614         {
    615             glGenTextures(1, (GLuint*)&kk->gl.id[i]);
    616             glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
    617             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    618             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    619             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8,
    620                          16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, empty_texture);
    621         }
    622 
    623         for(i = 0; i < 94; i++)
    624         {
    625             glDisable(GL_TEXTURE_2D);
    626             glClear(GL_COLOR_BUFFER_BIT);
    627 
    628             glColor3f(1, 1, 1);
    629             glRasterPos2f(0, 15);
    630             glutBitmapCharacter(GLUT_BITMAP_9_BY_15, i + 32);
    631 
    632             glEnable(GL_TEXTURE_2D);
    633             glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
    634             glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
    635                              0, kk->gl.height - 16, 16, 16, 0);
    636 
    637             glutMainLoopEvent();
    638             glutPostRedisplay();
    639         }
    640     }
    641     else
    642 #endif
    643     {
    644         /* Dummy */
    645     }
    646 
    647     kk->delay = 0;
    648     kk->rendertime = 0;
    649 
     70    cucul_set_size(kk->qq, kk->conio.ti.screenwidth,
     71                           kk->conio.ti.screenheight);
    65072    return 0;
    65173}
    65274
    653 int _caca_end_graphics(caca_t *kk)
     75int conio_end_graphics(caca_t *kk)
    65476{
    655 #if defined(USE_SLANG)
    656     /* Nothing to do */
    657 #endif
    658 #if defined(USE_NCURSES)
    659     /* Nothing to do */
    660 #endif
    661 #if defined(USE_CONIO)
    662     if(kk->driver == CACA_DRIVER_CONIO)
    663     {
    664         free(kk->conio.screen);
    665     }
    666     else
    667 #endif
    668 #if defined(USE_X11)
    669     if(kk->driver == CACA_DRIVER_X11)
    670     {
    671         XSync(kk->x11.dpy, False);
    672 #if defined(HAVE_X11_XKBLIB_H)
    673         if(!kk->x11.autorepeat)
    674             XAutoRepeatOn(kk->x11.dpy);
    675 #endif
    676         XFreePixmap(kk->x11.dpy, kk->x11.pixmap);
    677         XFreeFont(kk->x11.dpy, kk->x11.font_struct);
    678         XFreeGC(kk->x11.dpy, kk->x11.gc);
    679         XUnmapWindow(kk->x11.dpy, kk->x11.window);
    680         XDestroyWindow(kk->x11.dpy, kk->x11.window);
    681         XCloseDisplay(kk->x11.dpy);
    682     }
    683     else
    684 #endif
    685 #if defined(USE_WIN32)
    686     if(kk->driver == CACA_DRIVER_WIN32)
    687     {
    688         SetConsoleActiveScreenBuffer(kk->win32.hout);
    689         CloseHandle(kk->win32.back);
    690         CloseHandle(kk->win32.front);
    691     }
    692     else
    693 #endif
    694 #if defined(USE_GL)
    695     if(kk->driver == CACA_DRIVER_GL)
    696     {
    697         glutDestroyWindow(kk->gl.window);
    698     }
    699     else
    700 #endif
    701     {
    702         /* Dummy */
    703     }
     77    _wscroll = 1;
     78    textcolor((enum COLORS)WHITE);
     79    textbackground((enum COLORS)BLACK);
     80    gotoxy(_caca_width, _caca_height);
     81    cputs("\r\n");
     82    _setcursortype(_NORMALCURSOR);
     83
     84    free(kk->conio.screen);
    70485
    70586    return 0;
     
    70788#endif /* _DOXYGEN_SKIP_ME */
    70889
    709 /** \brief Set the window title.
    710  *
    711  *  If libcaca runs in a window, try to change its title. This works with
    712  *  the X11 and Win32 drivers.
    713  *
    714  *  \param title The desired window title.
    715  *  \return 0 upon success, a non-zero value if an error occurs.
    716  */
    717 int caca_set_window_title(caca_t *kk, char const *title)
     90int conio_set_window_title(caca_t *kk, char const *title)
    71891{
    719 #if defined(USE_X11)
    720     if(kk->driver == CACA_DRIVER_X11)
    721     {
    722         XStoreName(kk->x11.dpy, kk->x11.window, title);
    723     }
    724     else
    725 #endif
    726 #if defined(USE_WIN32)
    727     if(kk->driver == CACA_DRIVER_WIN32)
    728     {
    729         SetConsoleTitle(title);
    730     }
    731     else
    732 #endif
    733 #if defined(USE_GL)
    734     if(kk->driver == CACA_DRIVER_GL)
    735     {
    736         glutSetWindowTitle(title);
    737     }
    738     else
    739 #endif
    740     {
    741         /* Not supported */
    742         return -1;
    743     }
    744 
    74592    return 0;
    74693}
    74794
    748 /** \brief Get the window width.
    749  *
    750  *  If libcaca runs in a window, get the usable window width. This value can
    751  *  be used for aspect ratio calculation. If libcaca does not run in a window
    752  *  or if there is no way to know the font size, assume a 6x10 font is being
    753  *  used. Note that the units are not necessarily pixels.
    754  *
    755  *  \return The window width.
    756  */
    757 unsigned int caca_get_window_width(caca_t *kk)
     95unsigned int conio_get_window_width(caca_t *kk)
    75896{
    759 #if defined(USE_X11)
    760     if(kk->driver == CACA_DRIVER_X11)
    761     {
    762         return kk->qq->width * kk->x11.font_width;
    763     }
    764     else
    765 #endif
    766 #if defined(USE_WIN32)
    767     if(kk->driver == CACA_DRIVER_WIN32)
    768     {
    769         /* FIXME */
    770     }
    771     else
    772 #endif
    773 #if defined(USE_GL)
    774     if(kk->driver == CACA_DRIVER_GL)
    775     {
    776         return kk->gl.width;
    777     }
    778     else
    779 #endif
    780     {
    781         /* Dummy */
    782     }
    783 
    78497    /* Fallback to a 6x10 font */
    78598    return kk->qq->width * 6;
    78699}
    787100
    788 /** \brief Get the window height.
    789  *
    790  *  If libcaca runs in a window, get the usable window height. This value can
    791  *  be used for aspect ratio calculation. If libcaca does not run in a window
    792  *  or if there is no way to know the font size, assume a 6x10 font is being
    793  *  used. Note that the units are not necessarily pixels.
    794  *
    795  *  \return The window height.
    796  */
    797 unsigned int caca_get_window_height(caca_t *kk)
     101unsigned int conio_get_window_height(caca_t *kk)
    798102{
    799 #if defined(USE_X11)
    800     if(kk->driver == CACA_DRIVER_X11)
    801     {
    802         return kk->qq->height * kk->x11.font_height;
    803     }
    804     else
    805 #endif
    806 #if defined(USE_WIN32)
    807     if(kk->driver == CACA_DRIVER_WIN32)
    808     {
    809         /* FIXME */
    810     }
    811     else
    812 #endif
    813 #if defined(USE_GL)
    814     if(kk->driver == CACA_DRIVER_GL)
    815     {
    816         return kk->gl.height;
    817     }
    818     else
    819 #endif
    820     {
    821         /* Dummy */
    822     }
    823 
    824103    /* Fallback to a 6x10 font */
    825104    return kk->qq->height * 10;
    826105}
    827106
    828 /** \brief Set the refresh delay.
    829  *
    830  *  This function sets the refresh delay in microseconds. The refresh delay
    831  *  is used by caca_display() to achieve constant framerate. See the
    832  *  caca_display() documentation for more details.
    833  *
    834  *  If the argument is zero, constant framerate is disabled. This is the
    835  *  default behaviour.
    836  *
    837  *  \param usec The refresh delay in microseconds.
    838  */
    839 void caca_set_delay(caca_t *kk, unsigned int usec)
     107void conio_display(caca_t *kk)
    840108{
    841     kk->delay = usec;
     109    int n;
     110    char *screen = kk->conio.screen;
     111    uint8_t *attr = kk->qq->attr;
     112    uint32_t *chars = kk->qq->chars;
     113    for(n = kk->qq->height * kk->qq->width; n--; )
     114    {
     115        *screen++ = *chars++ & 0x7f;
     116        *screen++ = *attr++;
     117    }
     118#   if defined(SCREENUPDATE_IN_PC_H)
     119    ScreenUpdate(kk->conio.screen);
     120#   else
     121    /* FIXME */
     122#   endif
    842123}
    843124
    844 /** \brief Get the average rendering time.
    845  *
    846  *  This function returns the average rendering time, which is the average
    847  *  measured time between two caca_display() calls, in microseconds. If
    848  *  constant framerate was activated by calling caca_set_delay(), the average
    849  *  rendering time will not be considerably shorter than the requested delay
    850  *  even if the real rendering time was shorter.
    851  *
    852  *  \return The render time in microseconds.
    853  */
    854 unsigned int caca_get_rendertime(caca_t *kk)
     125void conio_handle_resize(caca_t *kk)
    855126{
    856     return kk->rendertime;
    857 }
    858 
    859 /** \brief Flush pending changes and redraw the screen.
    860  *
    861  *  This function flushes all graphical operations and prints them to the
    862  *  screen. Nothing will show on the screen until caca_display() is
    863  *  called.
    864  *
    865  *  If caca_set_delay() was called with a non-zero value, caca_display()
    866  *  will use that value to achieve constant framerate: if two consecutive
    867  *  calls to caca_display() are within a time range shorter than the value
    868  *  set with caca_set_delay(), the second call will wait a bit before
    869  *  performing the screen refresh.
    870  */
    871 void caca_display(caca_t *kk)
    872 {
    873 #if !defined(_DOXYGEN_SKIP_ME)
    874 #define IDLE_USEC 10000
    875 #endif
    876     int ticks = kk->lastticks + _caca_getticks(&kk->timer);
    877 
    878 #if defined(USE_SLANG)
    879     if(kk->driver == CACA_DRIVER_SLANG)
    880     {
    881         int x, y;
    882         uint8_t *attr = kk->qq->attr;
    883         uint32_t *chars = kk->qq->chars;
    884         for(y = 0; y < (int)kk->qq->height; y++)
    885         {
    886             SLsmg_gotorc(y, 0);
    887             for(x = kk->qq->width; x--; )
    888             {
    889 #if defined(OPTIMISE_SLANG_PALETTE)
    890                 /* If foreground == background, just don't use this colour
    891                  * pair, and print a space instead of the real character. */
    892                 uint8_t fgcolor = *attr & 0xf;
    893                 uint8_t bgcolor = *attr >> 4;
    894                 if(fgcolor != bgcolor)
    895                 {
    896                     SLsmg_set_color(slang_assoc[*attr++]);
    897                     SLsmg_write_char(*chars++ & 0x7f);
    898                 }
    899                 else
    900                 {
    901                     if(fgcolor == CUCUL_COLOR_BLACK)
    902                         fgcolor = CUCUL_COLOR_WHITE;
    903                     else if(fgcolor == CUCUL_COLOR_WHITE
    904                              || fgcolor <= CUCUL_COLOR_LIGHTGRAY)
    905                         fgcolor = CUCUL_COLOR_BLACK;
    906                     else
    907                         fgcolor = CUCUL_COLOR_WHITE;
    908                     SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]);
    909                     SLsmg_write_char(' ');
    910                     chars++;
    911                     attr++;
    912                 }
    913 #else
    914                 SLsmg_set_color(*attr++);
    915                 SLsmg_write_char(*chars++ & 0x7f);
    916 #endif
    917             }
    918         }
    919         SLsmg_refresh();
    920     }
    921     else
    922 #endif
    923 #if defined(USE_NCURSES)
    924     if(kk->driver == CACA_DRIVER_NCURSES)
    925     {
    926         int x, y;
    927         uint8_t *attr = kk->qq->attr;
    928         uint32_t *chars = kk->qq->chars;
    929         for(y = 0; y < (int)kk->qq->height; y++)
    930         {
    931             move(y, 0);
    932             for(x = kk->qq->width; x--; )
    933             {
    934                 attrset(kk->ncurses.attr[*attr++]);
    935                 addch(*chars++ & 0x7f);
    936             }
    937         }
    938         refresh();
    939     }
    940     else
    941 #endif
    942 #if defined(USE_CONIO)
    943     if(kk->driver == CACA_DRIVER_CONIO)
    944     {
    945         int n;
    946         char *screen = kk->conio.screen;
    947         uint8_t *attr = kk->qq->attr;
    948         uint32_t *chars = kk->qq->chars;
    949         for(n = kk->qq->height * kk->qq->width; n--; )
    950         {
    951             *screen++ = *chars++ & 0x7f;
    952             *screen++ = *attr++;
    953         }
    954 #   if defined(SCREENUPDATE_IN_PC_H)
    955         ScreenUpdate(kk->conio.screen);
    956 #   else
    957         /* FIXME */
    958 #   endif
    959     }
    960     else
    961 #endif
    962 #if defined(USE_X11)
    963     if(kk->driver == CACA_DRIVER_X11)
    964     {
    965         unsigned int x, y, len;
    966 
    967         /* First draw the background colours. Splitting the process in two
    968          * loops like this is actually slightly faster. */
    969         for(y = 0; y < kk->qq->height; y++)
    970         {
    971             for(x = 0; x < kk->qq->width; x += len)
    972             {
    973                 uint8_t *attr = kk->qq->attr + x + y * kk->qq->width;
    974 
    975                 len = 1;
    976                 while(x + len < kk->qq->width
    977                        && (attr[len] >> 4) == (attr[0] >> 4))
    978                     len++;
    979 
    980                 XSetForeground(kk->x11.dpy, kk->x11.gc,
    981                                kk->x11.colors[attr[0] >> 4]);
    982                 XFillRectangle(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc,
    983                                x * kk->x11.font_width, y * kk->x11.font_height,
    984                                len * kk->x11.font_width, kk->x11.font_height);
    985             }
    986         }
    987 
    988         /* Then print the foreground characters */
    989         for(y = 0; y < kk->qq->height; y++)
    990         {
    991             for(x = 0; x < kk->qq->width; x += len)
    992             {
    993                 char buffer[BUFSIZ]; /* FIXME: use a smaller buffer */
    994                 uint32_t *chars = kk->qq->chars + x + y * kk->qq->width;
    995                 uint8_t *attr = kk->qq->attr + x + y * kk->qq->width;
    996 
    997                 len = 1;
    998 
    999                 /* Skip spaces */
    1000                 if(chars[0] == ' ')
    1001                     continue;
    1002 
    1003                 buffer[0] = chars[0] & 0x7f;
    1004 
    1005                 while(x + len < kk->qq->width
    1006                        && (attr[len] & 0xf) == (attr[0] & 0xf))
    1007                 {
    1008                     buffer[len] = chars[len] & 0x7f;
    1009                     len++;
    1010                 }
    1011 
    1012                 XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[attr[0] & 0xf]);
    1013                 XDrawString(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc,
    1014                             x * kk->x11.font_width,
    1015                             (y + 1) * kk->x11.font_height - kk->x11.font_offset,
    1016                             buffer, len);
    1017             }
    1018         }
    1019 
    1020         XCopyArea(kk->x11.dpy, kk->x11.pixmap, kk->x11.window, kk->x11.gc, 0, 0,
    1021                   kk->qq->width * kk->x11.font_width, kk->qq->height * kk->x11.font_height,
    1022                   0, 0);
    1023         XFlush(kk->x11.dpy);
    1024     }
    1025     else
    1026 #endif
    1027 #if defined(USE_WIN32)
    1028     if(kk->driver == CACA_DRIVER_WIN32)
    1029     {
    1030         COORD size, pos;
    1031         SMALL_RECT rect;
    1032         unsigned int i;
    1033 
    1034         /* Render everything to our back buffer */
    1035         for(i = 0; i < kk->qq->width * kk->qq->height; i++)
    1036         {
    1037             kk->win32.buffer[i].Char.AsciiChar = kk->qq->chars[i] & 0x7f;
    1038             kk->win32.buffer[i].Attributes =
    1039                     win32_fg_palette[kk->qq->attr[i] & 0xf]
    1040                      | win32_bg_palette[kk->qq->attr[i] >> 4];
    1041         }
    1042 
    1043         /* Blit the back buffer to the front buffer */
    1044         size.X = kk->qq->width;
    1045         size.Y = kk->qq->height;
    1046         pos.X = pos.Y = 0;
    1047         rect.Left = rect.Top = 0;
    1048         rect.Right = kk->qq->width - 1;
    1049         rect.Bottom = kk->qq->height - 1;
    1050         WriteConsoleOutput(kk->win32.front, kk->win32.buffer, size, pos, &rect);
    1051     }
    1052     else
    1053 #endif
    1054 #if defined(USE_GL)
    1055     if(kk->driver == CACA_DRIVER_GL)
    1056     {
    1057         unsigned int x, y, line;
    1058 
    1059         glClear(GL_COLOR_BUFFER_BIT);
    1060 
    1061         line = 0;
    1062         for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
    1063         {
    1064             uint8_t *attr = kk->qq->attr + line * kk->qq->width;
    1065 
    1066             for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
    1067             {
    1068                 glDisable(GL_TEXTURE_2D);
    1069                 glColor4bv(gl_bgpal[attr[0] >> 4]);
    1070                 glBegin(GL_QUADS);
    1071                     glVertex2f(x, y);
    1072                     glVertex2f(x + kk->gl.font_width, y);
    1073                     glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height);
    1074                     glVertex2f(x, y + kk->gl.font_height);
    1075                 glEnd();
    1076 
    1077                 attr++;
    1078             }
    1079 
    1080             line++;
    1081         }
    1082 
    1083         /* 2nd pass, avoids changing render state too much */
    1084         glEnable(GL_BLEND);
    1085         glEnable(GL_TEXTURE_2D);
    1086         glBlendFunc(GL_ONE, GL_ONE);
    1087 
    1088         line = 0;
    1089         for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
    1090         {
    1091             uint8_t *attr = kk->qq->attr + line * kk->qq->width;
    1092             uint32_t *chars = kk->qq->chars + line * kk->qq->width;
    1093 
    1094             for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
    1095             {
    1096                 if(*chars != (uint32_t)' ')
    1097                 {
    1098                     char ch = *chars & 0x7f;
    1099 
    1100                     /* FIXME: check ch bounds */
    1101                     glBindTexture(GL_TEXTURE_2D, kk->gl.id[ch - 32]);
    1102                     glColor4bv(gl_bgpal[attr[0] & 0xf]);
    1103                     glBegin(GL_QUADS);
    1104                         glTexCoord2f(0, kk->gl.sh);
    1105                         glVertex2f(x, y);
    1106                         glTexCoord2f(kk->gl.sw, kk->gl.sh);
    1107                         glVertex2f(x + kk->gl.font_width, y);
    1108                         glTexCoord2f(kk->gl.sw, 0);
    1109                         glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height);
    1110                         glTexCoord2f(0, 0);
    1111                         glVertex2f(x, y + kk->gl.font_height);
    1112                     glEnd();
    1113                 }
    1114 
    1115                 attr++;
    1116                 chars++;
    1117             }
    1118             line++;
    1119         }
    1120         glDisable(GL_BLEND);
    1121         glDisable(GL_TEXTURE_2D);
    1122 
    1123         glutMainLoopEvent();
    1124         glutSwapBuffers();
    1125         glutPostRedisplay();
    1126     }
    1127     else
    1128 #endif
    1129     {
    1130         /* Dummy */
    1131     }
    1132 
    1133     /* FIXME handle this somewhere else */
    1134     if(kk->resize)
    1135     {
    1136         kk->resize = 0;
    1137         caca_handle_resize(kk);
    1138     }
    1139 
    1140     /* Wait until kk->delay + time of last call */
    1141     ticks += _caca_getticks(&kk->timer);
    1142     for(ticks += _caca_getticks(&kk->timer);
    1143         ticks + IDLE_USEC < (int)kk->delay;
    1144         ticks += _caca_getticks(&kk->timer))
    1145     {
    1146         _caca_sleep(IDLE_USEC);
    1147     }
    1148 
    1149     /* Update the sliding mean of the render time */
    1150     kk->rendertime = (7 * kk->rendertime + ticks) / 8;
    1151 
    1152     kk->lastticks = ticks - kk->delay;
    1153 
    1154     /* If we drifted too much, it's bad, bad, bad. */
    1155     if(kk->lastticks > (int)kk->delay)
    1156         kk->lastticks = 0;
     127    return;
    1157128}
    1158129
    1159130/*
    1160  * XXX: following functions are local
     131 * Driver initialisation
    1161132 */
    1162133
    1163 static void caca_handle_resize(caca_t *kk)
     134void conio_init_driver(caca_t *kk)
    1164135{
    1165     unsigned int new_width, new_height;
     136    kk->driver.driver = CACA_DRIVER_CONIO;
    1166137
    1167     new_width = kk->qq->width;
    1168     new_height = kk->qq->height;
    1169 
    1170 #if defined(USE_SLANG)
    1171     if(kk->driver == CACA_DRIVER_SLANG)
    1172     {
    1173         SLtt_get_screen_size();
    1174         new_width = SLtt_Screen_Cols;
    1175         new_height = SLtt_Screen_Rows;
    1176 
    1177         if(new_width != kk->qq->width || new_height != kk->qq->height)
    1178             SLsmg_reinit_smg();
    1179     }
    1180     else
    1181 #endif
    1182 #if defined(USE_NCURSES)
    1183     if(kk->driver == CACA_DRIVER_NCURSES)
    1184     {
    1185         struct winsize size;
    1186 
    1187         if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0)
    1188         {
    1189             new_width = size.ws_col;
    1190             new_height = size.ws_row;
    1191 #if defined(HAVE_RESIZE_TERM)
    1192             resize_term(new_height, new_width);
    1193 #else
    1194             resizeterm(new_height, new_width);
    1195 #endif
    1196             wrefresh(curscr);
    1197         }
    1198     }
    1199     else
    1200 #endif
    1201 #if defined(USE_CONIO)
    1202     if(kk->driver == CACA_DRIVER_CONIO)
    1203     {
    1204         /* Nothing to do here. */
    1205     }
    1206     else
    1207 #endif
    1208 #if defined(USE_X11)
    1209     if(kk->driver == CACA_DRIVER_X11)
    1210     {
    1211         Pixmap new_pixmap;
    1212 
    1213         new_width = kk->x11.new_width;
    1214         new_height = kk->x11.new_height;
    1215 
    1216         new_pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window,
    1217                                    kk->qq->width * kk->x11.font_width,
    1218                                    kk->qq->height * kk->x11.font_height,
    1219                                    DefaultDepth(kk->x11.dpy,
    1220                                                 DefaultScreen(kk->x11.dpy)));
    1221         XCopyArea(kk->x11.dpy, kk->x11.pixmap, new_pixmap, kk->x11.gc, 0, 0,
    1222                   kk->qq->width * kk->x11.font_width,
    1223                   kk->qq->height * kk->x11.font_height, 0, 0);
    1224         XFreePixmap(kk->x11.dpy, kk->x11.pixmap);
    1225         kk->x11.pixmap = new_pixmap;
    1226     }
    1227     else
    1228 #endif
    1229 #if defined(USE_WIN32)
    1230     if(kk->driver == CACA_DRIVER_WIN32)
    1231     {
    1232         /* Nothing to do here. */
    1233     }
    1234     else
    1235 #endif
    1236 #if defined(USE_GL)
    1237     if(kk->driver == CACA_DRIVER_GL)
    1238     {
    1239         kk->gl.width = kk->gl.new_width;
    1240         kk->gl.height = kk->gl.new_height;
    1241 
    1242         new_width = kk->gl.width / kk->gl.font_width;
    1243         new_height = (kk->gl.height / kk->gl.font_height) + 1;
    1244 
    1245         glMatrixMode(GL_PROJECTION);
    1246         glPushMatrix();
    1247         glLoadIdentity();
    1248 
    1249         glViewport(0, 0, kk->gl.width, kk->gl.height);
    1250         gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
    1251         glMatrixMode(GL_MODELVIEW);
    1252     }
    1253     else
    1254 #endif
    1255     {
    1256         /* Dummy */
    1257     }
    1258 
    1259     /* Tell libcucul we changed size */
    1260     if(new_width != kk->qq->width || new_height != kk->qq->height)
    1261         cucul_set_size(kk->qq, new_width, new_height);
     138    kk->driver.init_graphics = conio_init_graphics;
     139    kk->driver.end_graphics = conio_end_graphics;
     140    kk->driver.set_window_title = conio_set_window_title;
     141    kk->driver.get_window_width = conio_get_window_width;
     142    kk->driver.get_window_height = conio_get_window_height;
     143    kk->driver.display = conio_display;
     144    kk->driver.handle_resize = conio_handle_resize;
    1262145}
    1263146
    1264 #if defined(USE_SLANG)
    1265 static void slang_init_palette(void)
    1266 {
    1267     /* See SLang ref., 5.4.4. */
    1268     static char *slang_colors[16] =
    1269     {
    1270         /* Standard colours */
    1271         "black",
    1272         "blue",
    1273         "green",
    1274         "cyan",
    1275         "red",
    1276         "magenta",
    1277         "brown",
    1278         "lightgray",
    1279         /* Bright colours */
    1280         "gray",
    1281         "brightblue",
    1282         "brightgreen",
    1283         "brightcyan",
    1284         "brightred",
    1285         "brightmagenta",
    1286         "yellow",
    1287         "white",
    1288     };
     147#endif /* USE_CONIO */
    1289148
    1290 #if defined(OPTIMISE_SLANG_PALETTE)
    1291     int i;
    1292 
    1293     for(i = 0; i < 16 * 16; i++)
    1294         SLtt_set_color(i, NULL, slang_colors[slang_palette[i * 2]],
    1295                                 slang_colors[slang_palette[i * 2 + 1]]);
    1296 #else
    1297     int fg, bg;
    1298 
    1299     for(bg = 0; bg < 16; bg++)
    1300         for(fg = 0; fg < 16; fg++)
    1301         {
    1302             int i = fg + 16 * bg;
    1303             SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]);
    1304         }
    1305 #endif
    1306 }
    1307 #endif /* USE_SLANG */
    1308 
    1309 #if defined(USE_X11)
    1310 static int x11_error_handler(Display *dpy, XErrorEvent *event)
    1311 {
    1312     /* Ignore the error */
    1313     return 0;
    1314 }
    1315 #endif
    1316 
    1317 #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
    1318 static RETSIGTYPE sigwinch_handler(int sig)
    1319 {
    1320     sigwinch_kk->resize_event = 1;
    1321 
    1322     signal(SIGWINCH, sigwinch_handler);;
    1323 }
    1324 #endif
    1325 
    1326 #if defined(USE_GL)
    1327 static void gl_handle_keyboard(unsigned char key, int x, int y)
    1328 {
    1329     caca_t *kk = gl_kk;
    1330 
    1331     kk->gl.key = key;
    1332 }
    1333 
    1334 static void gl_handle_special_key(int key, int x, int y)
    1335 {
    1336     caca_t *kk = gl_kk;
    1337 
    1338     kk->gl.special_key = key;
    1339 }
    1340 
    1341 static void gl_handle_reshape(int w, int h)
    1342 {
    1343     caca_t *kk = gl_kk;
    1344 
    1345     if(kk->gl.bit) /* Do not handle reshaping at the first time */
    1346     {
    1347         kk->gl.new_width = w;
    1348         kk->gl.new_height = h;
    1349 
    1350         kk->gl.resized = 1;
    1351     }
    1352     else
    1353         kk->gl.bit = 1;
    1354 }
    1355 
    1356 static void gl_handle_mouse(int button, int state, int x, int y)
    1357 {
    1358     caca_t *kk = gl_kk;
    1359 
    1360     kk->gl.mouse_clicked = 1;
    1361     kk->gl.mouse_button = button;
    1362     kk->gl.mouse_state = state;
    1363     kk->gl.mouse_x = x / kk->gl.font_width;
    1364     kk->gl.mouse_y = y / kk->gl.font_height;
    1365     kk->gl.mouse_changed = 1;
    1366 }
    1367 
    1368 static void gl_handle_mouse_motion(int x, int y)
    1369 {
    1370     caca_t *kk = gl_kk;
    1371 
    1372     kk->gl.mouse_x = x / kk->gl.font_width;
    1373     kk->gl.mouse_y = y / kk->gl.font_height;
    1374     kk->gl.mouse_changed = 1;
    1375 }
    1376 #endif
    1377 
  • libcaca/trunk/caca/driver_gl.c

    r537 r539  
    2020#include "config.h"
    2121
    22 #if defined(USE_SLANG)
    23 #   if defined(HAVE_SLANG_SLANG_H)
    24 #       include <slang/slang.h>
    25 #   else
    26 #       include <slang.h>
    27 #   endif
    28 #endif
    29 #if defined(USE_NCURSES)
    30 #   if defined(HAVE_NCURSES_H)
    31 #       include <ncurses.h>
    32 #   else
    33 #       include <curses.h>
    34 #   endif
    35 #endif
    36 #if defined(USE_CONIO)
    37 #   include <conio.h>
    38 #   if defined(SCREENUPDATE_IN_PC_H)
    39 #       include <pc.h>
    40 #   endif
    41 #endif
    42 #if defined(USE_X11)
    43 #   include <X11/Xlib.h>
    44 #   if defined(HAVE_X11_XKBLIB_H)
    45 #       include <X11/XKBlib.h>
    46 #   endif
    47 #endif
    48 #if defined(USE_WIN32)
    49 #   include <windows.h>
    50 #endif
    51 #if defined(USE_GL)
    52 #   include <GL/gl.h>
    53 #   include <GL/glut.h>
    54 #   include <GL/freeglut_ext.h>
    55 #endif
    5622#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME)
    5723#   include <inttypes.h>
     
    6026typedef unsigned char uint8_t;
    6127#endif
     28
     29#if defined(USE_GL)
     30
     31#include <GL/gl.h>
     32#include <GL/glut.h>
     33#include <GL/freeglut_ext.h>
    6234
    6335#include <stdio.h> /* BUFSIZ */
     
    6941#include <stdarg.h>
    7042
    71 #if defined(HAVE_SIGNAL_H)
    72 #   include <signal.h>
    73 #endif
    74 #if defined(HAVE_SYS_IOCTL_H)
    75 #   include <sys/ioctl.h>
    76 #endif
    77 
    7843#include "caca.h"
    7944#include "caca_internals.h"
     
    8550 */
    8651
    87 #if defined(USE_SLANG)
    88 /* Tables generated by test/optipal.c */
    89 static int const slang_palette[2*16*16] =
    90 {
    91      1,  0,   2,  0,   3,  0,   4,  0,   5,  0,   6,  0,   7,  0,   8,  0,
    92      9,  0,  10,  0,  11,  0,  12,  0,  13,  0,  14,  0,  15,  0,   0,  8,
    93      8,  7,   7,  8,  15,  7,   7, 15,  15,  9,   9, 15,   1,  9,   9,  1,
    94      7,  9,   9,  7,   8,  1,   1,  8,   0,  1,  15, 10,  10, 15,   2, 10,
    95     10,  2,   7, 10,  10,  7,   8,  2,   2,  8,   0,  2,  15, 11,  11, 15,
    96      3, 11,  11,  3,   7, 11,  11,  7,   8,  3,   3,  8,   0,  3,  15, 12,
    97     12, 15,   4, 12,  12,  4,   7, 12,  12,  7,   8,  4,   4,  8,   0,  4,
    98     15, 13,  13, 15,   5, 13,  13,  5,   7, 13,  13,  7,   8,  5,   5,  8,
    99      0,  5,  15, 14,  14, 15,   6, 14,  14,  6,   7, 14,  14,  7,   8,  6,
    100      6,  8,   0,  6,   4,  6,   6,  4,  12, 14,  14, 12,   6,  2,   2,  6,
    101     14, 10,  10, 14,   2,  3,   3,  2,  10, 11,  11, 10,   3,  1,   1,  3,
    102     11,  9,   9, 11,   1,  5,   5,  1,   9, 13,  13,  9,   5,  4,   4,  5,
    103     13, 12,  12, 13,   4, 14,   6, 12,  12,  6,  14,  4,   6, 10,   2, 14,
    104     14,  2,  10,  6,   2, 11,   3, 10,  10,  3,  11,  2,   3,  9,   1, 11,
    105     11,  1,   9,  3,   1, 13,   5,  9,   9,  5,  13,  1,   5, 12,   4, 13,
    106     13,  4,  12,  5,   0,  7,   0, 15,  15,  8,   8, 15,  15,  1,   7,  1,
    107      1,  6,   2,  5,   3,  4,   4,  3,   5,  2,   6,  1,   0,  0,   1,  1,
    108      9,  6,  10,  5,  11,  4,  12,  3,  13,  2,  14,  1,   2,  2,   3,  3,
    109      4,  4,   5,  5,   6,  6,   7,  7,  14,  9,   1, 15,   8,  9,   8,  8,
    110      9,  9,   1,  7,   0,  9,   9,  8,   6,  9,  13, 10,   2, 15,   8, 10,
    111      7,  2,  15,  2,   2,  7,   0, 10,  10,  8,   5, 10,  12, 11,   3, 15,
    112      8, 11,   7,  3,  15,  3,   3,  7,   0, 11,  11,  8,   4, 11,  11, 12,
    113      4, 15,   8, 12,   7,  4,  15,  4,   4,  7,   0, 12,  12,  8,   3, 12,
    114     10, 13,   5, 15,   8, 13,   7,  5,  15,  5,   5,  7,   0, 13,  13,  8,
    115      2, 13,   9, 14,   6, 15,   8, 14,   7,  6,  15,  6,   6,  7,   0, 14,
    116     14,  8,   1, 14,   5,  6,   2,  4,  13, 14,  10, 12,   4,  2,   3,  6,
    117     12, 10,  11, 14,   6,  3,   1,  2,  14, 11,   9, 10,   2,  1,   5,  3,
    118     10,  9,  13, 11,   3,  5,   4,  1,  11, 13,  12,  9,   1,  4,   6,  5,
    119      9, 12,  14, 13,   5, 14,   2, 12,  13,  6,  10,  4,   4, 10,   3, 14,
    120     12,  2,  11,  6,   6, 11,   1, 10,  14,  3,   9,  2,   2,  9,   5, 11,
    121     10,  1,  13,  3,   3, 13,   4,  9,  11,  5,  12,  1,   1, 12,   6, 13,
    122      9,  4,  14,  5,  10, 10,  11, 11,  12, 12,  13, 13,  14, 14,  15, 15,
    123 };
    124 
    125 static int const slang_assoc[16*16] =
    126 {
    127     134, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
    128     28, 135, 214, 86, 219, 91, 133, 127, 26, 23, 240, 112, 245, 117, 141, 126,
    129     37, 211, 142, 83, 206, 132, 78, 160, 35, 237, 32, 109, 232, 140, 104, 161,
    130     46, 87, 82, 143, 131, 215, 210, 169, 44, 113, 108, 41, 139, 241, 236, 170,
    131     55, 222, 203, 130, 144, 94, 75, 178, 53, 248, 229, 138, 50, 120, 101, 179,
    132     64, 90, 129, 218, 95, 145, 223, 187, 62, 116, 137, 244, 121, 59, 249, 188,
    133     73, 128, 79, 207, 74, 202, 146, 196, 71, 136, 105, 233, 100, 228, 68, 197,
    134     122, 153, 162, 171, 180, 189, 198, 147, 16, 25, 34, 43, 52, 61, 70, 18,
    135     15, 27, 36, 45, 54, 63, 72, 17, 151, 155, 164, 173, 182, 191, 200, 124,
    136     154, 22, 238, 110, 243, 115, 156, 24, 150, 152, 216, 88, 221, 93, 148, 20,
    137     163, 235, 31, 107, 230, 165, 102, 33, 159, 213, 250, 85, 208, 157, 80, 29,
    138     172, 111, 106, 40, 174, 239, 234, 42, 168, 89, 84, 251, 166, 217, 212, 38,
    139     181, 246, 227, 183, 49, 118, 99, 51, 177, 224, 205, 175, 252, 96, 77, 47,
    140     190, 114, 192, 242, 119, 58, 247, 60, 186, 92, 184, 220, 97, 253, 225, 56,
    141     199, 201, 103, 231, 98, 226, 67, 69, 195, 193, 81, 209, 76, 204, 254, 65,
    142     123, 149, 158, 167, 176, 185, 194, 19, 125, 21, 30, 39, 48, 57, 66, 255,
    143 };
    144 #endif
    145 
    146 #if defined(USE_WIN32)
    147 static int const win32_fg_palette[] =
    148 {
    149     0,
    150     FOREGROUND_BLUE,
    151     FOREGROUND_GREEN,
    152     FOREGROUND_GREEN | FOREGROUND_BLUE,
    153     FOREGROUND_RED,
    154     FOREGROUND_RED | FOREGROUND_BLUE,
    155     FOREGROUND_RED | FOREGROUND_GREEN,
    156     FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
    157     FOREGROUND_INTENSITY,
    158     FOREGROUND_INTENSITY | FOREGROUND_BLUE,
    159     FOREGROUND_INTENSITY | FOREGROUND_GREEN,
    160     FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE,
    161     FOREGROUND_INTENSITY | FOREGROUND_RED,
    162     FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE,
    163     FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN,
    164     FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
    165 };
    166 
    167 static int const win32_bg_palette[] =
    168 {
    169     0,
    170     BACKGROUND_BLUE,
    171     BACKGROUND_GREEN,
    172     BACKGROUND_GREEN | BACKGROUND_BLUE,
    173     BACKGROUND_RED,
    174     BACKGROUND_RED | BACKGROUND_BLUE,
    175     BACKGROUND_RED | BACKGROUND_GREEN,
    176     BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
    177     BACKGROUND_INTENSITY,
    178     BACKGROUND_INTENSITY | BACKGROUND_BLUE,
    179     BACKGROUND_INTENSITY | BACKGROUND_GREEN,
    180     BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE,
    181     BACKGROUND_INTENSITY | BACKGROUND_RED,
    182     BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE,
    183     BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN,
    184     BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
    185 };
    186 #endif
    187 
    188 #if defined(USE_GL)
    18952/* Ok, I just suck. */
    19053static GLbyte const gl_bgpal[][4] =
     
    21073
    21174static caca_t *gl_kk; /* FIXME: we ought to get rid of this */
    212 #endif
    21375
    21476/*
    21577 * Local functions
    21678 */
    217 static void caca_handle_resize(caca_t *kk);
    218 
    219 #if defined(USE_SLANG)
    220 static void slang_init_palette(void);
    221 #endif
    222 
    223 #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
    224 static RETSIGTYPE sigwinch_handler(int);
    225 static caca_t *sigwinch_kk; /* FIXME: we ought to get rid of this */
    226 #endif
    227 
    228 #if defined(USE_X11)
    229 static int x11_error_handler(Display *, XErrorEvent *);
    230 #endif
    231 
    232 #if defined(USE_GL)
    23379static void gl_handle_keyboard(unsigned char, int, int);
    23480static void gl_handle_special_key(int, int, int);
     
    23682static void gl_handle_mouse(int, int, int, int);
    23783static void gl_handle_mouse_motion(int, int);
    238 #endif
    239 
    240 #if !defined(_DOXYGEN_SKIP_ME)
    241 int _caca_init_graphics(caca_t *kk)
    242 {
    243 #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
    244     sigwinch_kk = kk;
    245     signal(SIGWINCH, sigwinch_handler);
    246 #endif
    247 
    248 #if defined(USE_SLANG)
    249     if(kk->driver == CACA_DRIVER_SLANG)
    250     {
    251         slang_init_palette();
    252 
    253         /* Disable alt charset support so that we get a chance to have all
    254          * 256 colour pairs */
    255         SLtt_Has_Alt_Charset = 0;
    256 
    257         cucul_set_size(kk->qq, SLtt_Screen_Cols, SLtt_Screen_Rows);
    258     }
    259     else
    260 #endif
    261 #if defined(USE_NCURSES)
    262     if(kk->driver == CACA_DRIVER_NCURSES)
    263     {
    264         static int curses_colors[] =
    265         {
    266             /* Standard curses colours */
    267             COLOR_BLACK,
    268             COLOR_BLUE,
    269             COLOR_GREEN,
    270             COLOR_CYAN,
    271             COLOR_RED,
    272             COLOR_MAGENTA,
    273             COLOR_YELLOW,
    274             COLOR_WHITE,
    275             /* Extra values for xterm-16color */
    276             COLOR_BLACK + 8,
    277             COLOR_BLUE + 8,
    278             COLOR_GREEN + 8,
    279             COLOR_CYAN + 8,
    280             COLOR_RED + 8,
    281             COLOR_MAGENTA + 8,
    282             COLOR_YELLOW + 8,
    283             COLOR_WHITE + 8
    284         };
    285 
    286         int fg, bg, max;
    287 
    288         /* Activate colour */
    289         start_color();
    290 
    291         /* If COLORS == 16, it means the terminal supports full bright colours
    292          * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
    293          * we can build 16*16 colour pairs.
    294          * If COLORS == 8, it means the terminal does not know about bright
    295          * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
    296          * and \e[5m). We can only build 8*8 colour pairs. */
    297         max = COLORS >= 16 ? 16 : 8;
    298 
    299         for(bg = 0; bg < max; bg++)
    300             for(fg = 0; fg < max; fg++)
    301             {
    302                 /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
    303                  * is light gray on black. Some terminals don't like this
    304                  * colour pair to be redefined. */
    305                 int col = ((max + 7 - fg) % max) + max * bg;
    306                 init_pair(col, curses_colors[fg], curses_colors[bg]);
    307                 kk->ncurses.attr[fg + 16 * bg] = COLOR_PAIR(col);
    308 
    309                 if(max == 8)
    310                 {
    311                     /* Bright fg on simple bg */
    312                     kk->ncurses.attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
    313                     /* Simple fg on bright bg */
    314                     kk->ncurses.attr[fg + 16 * (bg + 8)] = A_BLINK
    315                                                         | COLOR_PAIR(col);
    316                     /* Bright fg on bright bg */
    317                     kk->ncurses.attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
    318                                                             | COLOR_PAIR(col);
    319                 }
    320             }
    321 
    322         cucul_set_size(kk->qq, COLS, LINES);
    323     }
    324     else
    325 #endif
    326 #if defined(USE_CONIO)
    327     if(kk->driver == CACA_DRIVER_CONIO)
    328     {
    329         gettextinfo(&kk->conio.ti);
    330         kk->conio.screen = malloc(2 * kk->conio.ti.screenwidth
    331                                 * kk->conio.ti.screenheight * sizeof(char));
    332         if(kk->conio.screen == NULL)
    333             return -1;
    334 #   if defined(SCREENUPDATE_IN_PC_H)
    335         ScreenRetrieve(kk->conio.screen);
    336 #   else
    337         /* FIXME */
    338 #   endif
    339         cucul_set_size(kk->qq, kk->conio.ti.screenwidth,
    340                                kk->conio.ti.screenheight);
    341     }
    342     else
    343 #endif
    344 #if defined(USE_X11)
    345     if(kk->driver == CACA_DRIVER_X11)
    346     {
    347         static int const x11_palette[] =
    348         {
    349             /* Standard curses colours */
    350             0x0,    0x0,    0x0,
    351             0x0,    0x0,    0x8000,
    352             0x0,    0x8000, 0x0,
    353             0x0,    0x8000, 0x8000,
    354             0x8000, 0x0,    0x0,
    355             0x8000, 0x0,    0x8000,
    356             0x8000, 0x8000, 0x0,
    357             0x8000, 0x8000, 0x8000,
    358             /* Extra values for xterm-16color */
    359             0x4000, 0x4000, 0x4000,
    360             0x4000, 0x4000, 0xffff,
    361             0x4000, 0xffff, 0x4000,
    362             0x4000, 0xffff, 0xffff,
    363             0xffff, 0x4000, 0x4000,
    364             0xffff, 0x4000, 0xffff,
    365             0xffff, 0xffff, 0x4000,
    366             0xffff, 0xffff, 0xffff,
    367         };
    368 
    369         Colormap colormap;
    370         XSetWindowAttributes x11_winattr;
    371         int (*old_error_handler)(Display *, XErrorEvent *);
    372         char const *fonts[] = { NULL, "8x13bold", "fixed" }, **parser;
    373         char const *geometry;
    374         unsigned int width = 0, height = 0;
    375         int i;
    376 
    377         geometry = getenv("CACA_GEOMETRY");
    378         if(geometry && *(geometry))
    379             sscanf(geometry, "%ux%u", &width, &height);
    380 
    381         if(width && height)
    382             cucul_set_size(kk->qq, width, height);
    383 
    384         kk->x11.dpy = XOpenDisplay(NULL);
    385         if(kk->x11.dpy == NULL)
    386             return -1;
    387 
    388         fonts[0] = getenv("CACA_FONT");
    389         if(fonts[0] && *fonts[0])
    390             parser = fonts;
    391         else
    392             parser = fonts + 1;
    393 
    394         /* Ignore font errors */
    395         old_error_handler = XSetErrorHandler(x11_error_handler);
    396 
    397         /* Parse our font list */
    398         for( ; ; parser++)
    399         {
    400             if(!*parser)
    401             {
    402                 XSetErrorHandler(old_error_handler);
    403                 XCloseDisplay(kk->x11.dpy);
    404                 return -1;
    405             }
    406 
    407             kk->x11.font = XLoadFont(kk->x11.dpy, *parser);
    408             if(!kk->x11.font)
    409                 continue;
    410 
    411             kk->x11.font_struct = XQueryFont(kk->x11.dpy, kk->x11.font);
    412             if(!kk->x11.font_struct)
    413             {
    414                 XUnloadFont(kk->x11.dpy, kk->x11.font);
    415                 continue;
    416             }
    417 
    418             break;
    419         }
    420 
    421         /* Reset the default X11 error handler */
    422         XSetErrorHandler(old_error_handler);
    423 
    424         kk->x11.font_width = kk->x11.font_struct->max_bounds.width;
    425         kk->x11.font_height = kk->x11.font_struct->max_bounds.ascent
    426                              + kk->x11.font_struct->max_bounds.descent;
    427         kk->x11.font_offset = kk->x11.font_struct->max_bounds.descent;
    428 
    429         colormap = DefaultColormap(kk->x11.dpy, DefaultScreen(kk->x11.dpy));
    430         for(i = 0; i < 16; i++)
    431         {
    432             XColor color;
    433             color.red = x11_palette[i * 3];
    434             color.green = x11_palette[i * 3 + 1];
    435             color.blue = x11_palette[i * 3 + 2];
    436             XAllocColor(kk->x11.dpy, colormap, &color);
    437             kk->x11.colors[i] = color.pixel;
    438         }
    439 
    440         x11_winattr.backing_store = Always;
    441         x11_winattr.background_pixel = kk->x11.colors[0];
    442         x11_winattr.event_mask = ExposureMask | StructureNotifyMask;
    443 
    444         kk->x11.window =
    445             XCreateWindow(kk->x11.dpy, DefaultRootWindow(kk->x11.dpy), 0, 0,
    446                           kk->qq->width * kk->x11.font_width,
    447                           kk->qq->height * kk->x11.font_height,
    448                           0, 0, InputOutput, 0,
    449                           CWBackingStore | CWBackPixel | CWEventMask,
    450                           &x11_winattr);
    451 
    452         XStoreName(kk->x11.dpy, kk->x11.window, "caca for X");
    453 
    454         XSelectInput(kk->x11.dpy, kk->x11.window, StructureNotifyMask);
    455         XMapWindow(kk->x11.dpy, kk->x11.window);
    456 
    457         kk->x11.gc = XCreateGC(kk->x11.dpy, kk->x11.window, 0, NULL);
    458         XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[15]);
    459         XSetFont(kk->x11.dpy, kk->x11.gc, kk->x11.font);
    460 
    461         for(;;)
    462         {
    463             XEvent event;
    464             XNextEvent(kk->x11.dpy, &event);
    465             if (event.type == MapNotify)
    466                 break;
    467         }
    468 
    469 #if defined(HAVE_X11_XKBLIB_H)
    470         /* Disable autorepeat */
    471         XkbSetDetectableAutoRepeat(kk->x11.dpy, True, &kk->x11.autorepeat);
    472         if(!kk->x11.autorepeat)
    473             XAutoRepeatOff(kk->x11.dpy);
    474 #endif
    475 
    476         XSelectInput(kk->x11.dpy, kk->x11.window, kk->x11.event_mask);
    477 
    478         XSync(kk->x11.dpy, False);
    479 
    480         kk->x11.pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window,
    481                                        kk->qq->width * kk->x11.font_width,
    482                                        kk->qq->height * kk->x11.font_height,
    483                                        DefaultDepth(kk->x11.dpy,
    484                                                 DefaultScreen(kk->x11.dpy)));
    485 
    486         kk->x11.new_width = kk->x11.new_height = 0;
    487     }
    488     else
    489 #endif
    490 #if defined(USE_WIN32)
    491     if(kk->driver == CACA_DRIVER_WIN32)
    492     {
    493         CONSOLE_CURSOR_INFO cci;
    494         CONSOLE_SCREEN_BUFFER_INFO csbi;
    495         COORD size;
    496 
    497         kk->win32.front =
    498             CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
    499                                       0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    500         if(!kk->win32.front || kk->win32.front == INVALID_HANDLE_VALUE)
    501             return -1;
    502 
    503         kk->win32.back =
    504             CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
    505                                       0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    506         if(!kk->win32.back || kk->win32.back == INVALID_HANDLE_VALUE)
    507             return -1;
    508 
    509         if(!GetConsoleScreenBufferInfo(kk->win32.hout, &csbi))
    510             return -1;
    511 
    512         /* Sample code to get the biggest possible window */
    513         //size = GetLargestConsoleWindowSize(kk->win32.hout);
    514         cucul_set_size(kk->qq, csbi.srWindow.Right - csbi.srWindow.Left + 1,
    515                                csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
    516         size.X = kk->qq->width;
    517         size.Y = kk->qq->height;
    518         SetConsoleScreenBufferSize(kk->win32.front, size);
    519         SetConsoleScreenBufferSize(kk->win32.back, size);
    520 
    521         SetConsoleMode(kk->win32.front, 0);
    522         SetConsoleMode(kk->win32.back, 0);
    523 
    524         GetConsoleCursorInfo(kk->win32.front, &cci);
    525         cci.dwSize = 0;
    526         cci.bVisible = FALSE;
    527         SetConsoleCursorInfo(kk->win32.front, &cci);
    528         SetConsoleCursorInfo(kk->win32.back, &cci);
    529 
    530         SetConsoleActiveScreenBuffer(kk->win32.front);
    531 
    532         kk->win32.buffer = malloc(kk->qq->width * kk->qq->height
    533                                    * sizeof(CHAR_INFO));
    534         if(kk->win32.buffer == NULL)
    535             return -1;
    536     }
    537     else
    538 #endif
    539 #if defined(USE_GL)
    540     if(kk->driver == CACA_DRIVER_GL)
    541     {
    542         char *empty_texture;
    543         char const *geometry;
    544         char *argv[2] = { "", NULL };
    545         unsigned int width = 0, height = 0;
    546         int argc = 1;
    547         int i;
    548 
    549         gl_kk = kk;
    550 
    551         geometry = getenv("CACA_GEOMETRY");
    552         if(geometry && *(geometry))
    553             sscanf(geometry, "%ux%u", &width, &height);
    554 
    555         if(width && height)
    556             cucul_set_size(kk->qq, width, height);
    557 
    558         kk->gl.font_width = 9;
    559         kk->gl.font_height = 15;
    560 
    561         kk->gl.width = kk->qq->width * kk->gl.font_width;
    562         kk->gl.height = kk->qq->height * kk->gl.font_height;
    563 
    564         kk->gl.resized = 0;
    565         kk->gl.bit = 0;
    566 
    567         kk->gl.mouse_changed = kk->gl.mouse_clicked = 0;
    568         kk->gl.mouse_button = kk->gl.mouse_state = 0;
    569 
    570         kk->gl.key = 0;
    571         kk->gl.special_key = 0;
    572 
    573         kk->gl.sw = 9.0f / 16.0f;
    574         kk->gl.sh = 15.0f / 16.0f;
    575 
    576         glutInit(&argc, argv);
    577 
    578         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    579         glutInitWindowSize(kk->gl.width, kk->gl.height);
    580         kk->gl.window = glutCreateWindow("caca for GL");
    581 
    582         gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
    583 
    584         glDisable(GL_CULL_FACE);
    585         glDisable(GL_DEPTH_TEST);
    586 
    587         glutKeyboardFunc(gl_handle_keyboard);
    588         glutSpecialFunc(gl_handle_special_key);
    589         glutReshapeFunc(gl_handle_reshape);
    590 
    591         glutMouseFunc(gl_handle_mouse);
    592         glutMotionFunc(gl_handle_mouse_motion);
    593         glutPassiveMotionFunc(gl_handle_mouse_motion);
    594 
    595         glLoadIdentity();
    596 
    597         glMatrixMode(GL_PROJECTION);
    598         glPushMatrix();
    599         glLoadIdentity();
    600         gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
    601 
    602         glMatrixMode(GL_MODELVIEW);
    603 
     84
     85int gl_init_graphics(caca_t *kk)
     86{
     87    char *empty_texture;
     88    char const *geometry;
     89    char *argv[2] = { "", NULL };
     90    unsigned int width = 0, height = 0;
     91    int argc = 1;
     92    int i;
     93
     94    gl_kk = kk;
     95
     96    geometry = getenv("CACA_GEOMETRY");
     97    if(geometry && *(geometry))
     98        sscanf(geometry, "%ux%u", &width, &height);
     99
     100    if(width && height)
     101        cucul_set_size(kk->qq, width, height);
     102
     103    kk->gl.font_width = 9;
     104    kk->gl.font_height = 15;
     105
     106    kk->gl.width = kk->qq->width * kk->gl.font_width;
     107    kk->gl.height = kk->qq->height * kk->gl.font_height;
     108
     109    kk->gl.resized = 0;
     110    kk->gl.bit = 0;
     111
     112    kk->gl.mouse_changed = kk->gl.mouse_clicked = 0;
     113    kk->gl.mouse_button = kk->gl.mouse_state = 0;
     114
     115    kk->gl.key = 0;
     116    kk->gl.special_key = 0;
     117
     118    kk->gl.sw = 9.0f / 16.0f;
     119    kk->gl.sh = 15.0f / 16.0f;
     120
     121    glutInit(&argc, argv);
     122
     123    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
     124    glutInitWindowSize(kk->gl.width, kk->gl.height);
     125    kk->gl.window = glutCreateWindow("caca for GL");
     126
     127    gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
     128
     129    glDisable(GL_CULL_FACE);
     130    glDisable(GL_DEPTH_TEST);
     131
     132    glutKeyboardFunc(gl_handle_keyboard);
     133    glutSpecialFunc(gl_handle_special_key);
     134    glutReshapeFunc(gl_handle_reshape);
     135
     136    glutMouseFunc(gl_handle_mouse);
     137    glutMotionFunc(gl_handle_mouse_motion);
     138    glutPassiveMotionFunc(gl_handle_mouse_motion);
     139
     140    glLoadIdentity();
     141
     142    glMatrixMode(GL_PROJECTION);
     143    glPushMatrix();
     144    glLoadIdentity();
     145    gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
     146
     147    glMatrixMode(GL_MODELVIEW);
     148
     149    glClear(GL_COLOR_BUFFER_BIT);
     150
     151    empty_texture = malloc(16 * 16 * 4);
     152    if(empty_texture == NULL)
     153        return -1;
     154
     155    memset(empty_texture, 0xff, 16 * 16 * 4);
     156    glEnable(GL_TEXTURE_2D);
     157
     158    for(i = 0; i < 94; i++)
     159    {
     160        glGenTextures(1, (GLuint*)&kk->gl.id[i]);
     161        glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
     162        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     163        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     164        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8,
     165                     16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, empty_texture);
     166    }
     167
     168    for(i = 0; i < 94; i++)
     169    {
     170        glDisable(GL_TEXTURE_2D);
    604171        glClear(GL_COLOR_BUFFER_BIT);
    605172
    606         empty_texture = malloc(16 * 16 * 4);
    607         if(empty_texture == NULL)
    608             return -1;
    609 
    610         memset(empty_texture, 0xff, 16 * 16 * 4);
     173        glColor3f(1, 1, 1);
     174        glRasterPos2f(0, 15);
     175        glutBitmapCharacter(GLUT_BITMAP_9_BY_15, i + 32);
     176
    611177        glEnable(GL_TEXTURE_2D);
    612 
    613         for(i = 0; i < 94; i++)
    614         {
    615             glGenTextures(1, (GLuint*)&kk->gl.id[i]);
    616             glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
    617             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    618             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    619             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8,
    620                          16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, empty_texture);
    621         }
    622 
    623         for(i = 0; i < 94; i++)
     178        glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
     179        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
     180                         0, kk->gl.height - 16, 16, 16, 0);
     181
     182        glutMainLoopEvent();
     183        glutPostRedisplay();
     184    }
     185
     186    return 0;
     187}
     188
     189int gl_end_graphics(caca_t *kk)
     190{
     191    glutDestroyWindow(kk->gl.window);
     192    return 0;
     193}
     194
     195int gl_set_window_title(caca_t *kk, char const *title)
     196{
     197    glutSetWindowTitle(title);
     198    return 0;
     199}
     200
     201unsigned int gl_get_window_width(caca_t *kk)
     202{
     203    return kk->gl.width;
     204}
     205
     206unsigned int gl_get_window_height(caca_t *kk)
     207{
     208    return kk->gl.height;
     209}
     210
     211void gl_display(caca_t *kk)
     212{
     213    unsigned int x, y, line;
     214
     215    glClear(GL_COLOR_BUFFER_BIT);
     216
     217    line = 0;
     218    for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
     219    {
     220        uint8_t *attr = kk->qq->attr + line * kk->qq->width;
     221
     222        for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
    624223        {
    625224            glDisable(GL_TEXTURE_2D);
    626             glClear(GL_COLOR_BUFFER_BIT);
    627 
    628             glColor3f(1, 1, 1);
    629             glRasterPos2f(0, 15);
    630             glutBitmapCharacter(GLUT_BITMAP_9_BY_15, i + 32);
    631 
    632             glEnable(GL_TEXTURE_2D);
    633             glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
    634             glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
    635                              0, kk->gl.height - 16, 16, 16, 0);
    636 
    637             glutMainLoopEvent();
    638             glutPostRedisplay();
     225            glColor4bv(gl_bgpal[attr[0] >> 4]);
     226            glBegin(GL_QUADS);
     227                glVertex2f(x, y);
     228                glVertex2f(x + kk->gl.font_width, y);
     229                glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height);
     230                glVertex2f(x, y + kk->gl.font_height);
     231            glEnd();
     232
     233            attr++;
    639234        }
    640     }
    641     else
    642 #endif
    643     {
    644         /* Dummy */
    645     }
    646 
    647     kk->delay = 0;
    648     kk->rendertime = 0;
    649 
    650     return 0;
    651 }
    652 
    653 int _caca_end_graphics(caca_t *kk)
    654 {
    655 #if defined(USE_SLANG)
    656     /* Nothing to do */
    657 #endif
    658 #if defined(USE_NCURSES)
    659     /* Nothing to do */
    660 #endif
    661 #if defined(USE_CONIO)
    662     if(kk->driver == CACA_DRIVER_CONIO)
    663     {
    664         free(kk->conio.screen);
    665     }
    666     else
    667 #endif
    668 #if defined(USE_X11)
    669     if(kk->driver == CACA_DRIVER_X11)
    670     {
    671         XSync(kk->x11.dpy, False);
    672 #if defined(HAVE_X11_XKBLIB_H)
    673         if(!kk->x11.autorepeat)
    674             XAutoRepeatOn(kk->x11.dpy);
    675 #endif
    676         XFreePixmap(kk->x11.dpy, kk->x11.pixmap);
    677         XFreeFont(kk->x11.dpy, kk->x11.font_struct);
    678         XFreeGC(kk->x11.dpy, kk->x11.gc);
    679         XUnmapWindow(kk->x11.dpy, kk->x11.window);
    680         XDestroyWindow(kk->x11.dpy, kk->x11.window);
    681         XCloseDisplay(kk->x11.dpy);
    682     }
    683     else
    684 #endif
    685 #if defined(USE_WIN32)
    686     if(kk->driver == CACA_DRIVER_WIN32)
    687     {
    688         SetConsoleActiveScreenBuffer(kk->win32.hout);
    689         CloseHandle(kk->win32.back);
    690         CloseHandle(kk->win32.front);
    691     }
    692     else
    693 #endif
    694 #if defined(USE_GL)
    695     if(kk->driver == CACA_DRIVER_GL)
    696     {
    697         glutDestroyWindow(kk->gl.window);
    698     }
    699     else
    700 #endif
    701     {
    702         /* Dummy */
    703     }
    704 
    705     return 0;
    706 }
    707 #endif /* _DOXYGEN_SKIP_ME */
    708 
    709 /** \brief Set the window title.
    710  *
    711  *  If libcaca runs in a window, try to change its title. This works with
    712  *  the X11 and Win32 drivers.
    713  *
    714  *  \param title The desired window title.
    715  *  \return 0 upon success, a non-zero value if an error occurs.
    716  */
    717 int caca_set_window_title(caca_t *kk, char const *title)
    718 {
    719 #if defined(USE_X11)
    720     if(kk->driver == CACA_DRIVER_X11)
    721     {
    722         XStoreName(kk->x11.dpy, kk->x11.window, title);
    723     }
    724     else
    725 #endif
    726 #if defined(USE_WIN32)
    727     if(kk->driver == CACA_DRIVER_WIN32)
    728     {
    729         SetConsoleTitle(title);
    730     }
    731     else
    732 #endif
    733 #if defined(USE_GL)
    734     if(kk->driver == CACA_DRIVER_GL)
    735     {
    736         glutSetWindowTitle(title);
    737     }
    738     else
    739 #endif
    740     {
    741         /* Not supported */
    742         return -1;
    743     }
    744 
    745     return 0;
    746 }
    747 
    748 /** \brief Get the window width.
    749  *
    750  *  If libcaca runs in a window, get the usable window width. This value can
    751  *  be used for aspect ratio calculation. If libcaca does not run in a window
    752  *  or if there is no way to know the font size, assume a 6x10 font is being
    753  *  used. Note that the units are not necessarily pixels.
    754  *
    755  *  \return The window width.
    756  */
    757 unsigned int caca_get_window_width(caca_t *kk)
    758 {
    759 #if defined(USE_X11)
    760     if(kk->driver == CACA_DRIVER_X11)
    761     {
    762         return kk->qq->width * kk->x11.font_width;
    763     }
    764     else
    765 #endif
    766 #if defined(USE_WIN32)
    767     if(kk->driver == CACA_DRIVER_WIN32)
    768     {
    769         /* FIXME */
    770     }
    771     else
    772 #endif
    773 #if defined(USE_GL)
    774     if(kk->driver == CACA_DRIVER_GL)
    775     {
    776         return kk->gl.width;
    777     }
    778     else
    779 #endif
    780     {
    781         /* Dummy */
    782     }
    783 
    784     /* Fallback to a 6x10 font */
    785     return kk->qq->width * 6;
    786 }
    787 
    788 /** \brief Get the window height.
    789  *
    790  *  If libcaca runs in a window, get the usable window height. This value can
    791  *  be used for aspect ratio calculation. If libcaca does not run in a window
    792  *  or if there is no way to know the font size, assume a 6x10 font is being
    793  *  used. Note that the units are not necessarily pixels.
    794  *
    795  *  \return The window height.
    796  */
    797 unsigned int caca_get_window_height(caca_t *kk)
    798 {
    799 #if defined(USE_X11)
    800     if(kk->driver == CACA_DRIVER_X11)
    801     {
    802         return kk->qq->height * kk->x11.font_height;
    803     }
    804     else
    805 #endif
    806 #if defined(USE_WIN32)
    807     if(kk->driver == CACA_DRIVER_WIN32)
    808     {
    809         /* FIXME */
    810     }
    811     else
    812 #endif
    813 #if defined(USE_GL)
    814     if(kk->driver == CACA_DRIVER_GL)
    815     {
    816         return kk->gl.height;
    817     }
    818     else
    819 #endif
    820     {
    821         /* Dummy */
    822     }
    823 
    824     /* Fallback to a 6x10 font */
    825     return kk->qq->height * 10;
    826 }
    827 
    828 /** \brief Set the refresh delay.
    829  *
    830  *  This function sets the refresh delay in microseconds. The refresh delay
    831  *  is used by caca_display() to achieve constant framerate. See the
    832  *  caca_display() documentation for more details.
    833  *
    834  *  If the argument is zero, constant framerate is disabled. This is the
    835  *  default behaviour.
    836  *
    837  *  \param usec The refresh delay in microseconds.
    838  */
    839 void caca_set_delay(caca_t *kk, unsigned int usec)
    840 {
    841     kk->delay = usec;
    842 }
    843 
    844 /** \brief Get the average rendering time.
    845  *
    846  *  This function returns the average rendering time, which is the average
    847  *  measured time between two caca_display() calls, in microseconds. If
    848  *  constant framerate was activated by calling caca_set_delay(), the average
    849  *  rendering time will not be considerably shorter than the requested delay
    850  *  even if the real rendering time was shorter.
    851  *
    852  *  \return The render time in microseconds.
    853  */
    854 unsigned int caca_get_rendertime(caca_t *kk)
    855 {
    856     return kk->rendertime;
    857 }
    858 
    859 /** \brief Flush pending changes and redraw the screen.
    860  *
    861  *  This function flushes all graphical operations and prints them to the
    862  *  screen. Nothing will show on the screen until caca_display() is
    863  *  called.
    864  *
    865  *  If caca_set_delay() was called with a non-zero value, caca_display()
    866  *  will use that value to achieve constant framerate: if two consecutive
    867  *  calls to caca_display() are within a time range shorter than the value
    868  *  set with caca_set_delay(), the second call will wait a bit before
    869  *  performing the screen refresh.
    870  */
    871 void caca_display(caca_t *kk)
    872 {
    873 #if !defined(_DOXYGEN_SKIP_ME)
    874 #define IDLE_USEC 10000
    875 #endif
    876     int ticks = kk->lastticks + _caca_getticks(&kk->timer);
    877 
    878 #if defined(USE_SLANG)
    879     if(kk->driver == CACA_DRIVER_SLANG)
    880     {
    881         int x, y;
    882         uint8_t *attr = kk->qq->attr;
    883         uint32_t *chars = kk->qq->chars;
    884         for(y = 0; y < (int)kk->qq->height; y++)
     235
     236        line++;
     237    }
     238
     239    /* 2nd pass, avoids changing render state too much */
     240    glEnable(GL_BLEND);
     241    glEnable(GL_TEXTURE_2D);
     242    glBlendFunc(GL_ONE, GL_ONE);
     243
     244    line = 0;
     245    for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
     246    {
     247        uint8_t *attr = kk->qq->attr + line * kk->qq->width;
     248        uint32_t *chars = kk->qq->chars + line * kk->qq->width;
     249
     250        for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
    885251        {
    886             SLsmg_gotorc(y, 0);
    887             for(x = kk->qq->width; x--; )
     252            if(*chars != (uint32_t)' ')
    888253            {
    889 #if defined(OPTIMISE_SLANG_PALETTE)
    890                 /* If foreground == background, just don't use this colour
    891                  * pair, and print a space instead of the real character. */
    892                 uint8_t fgcolor = *attr & 0xf;
    893                 uint8_t bgcolor = *attr >> 4;
    894                 if(fgcolor != bgcolor)
    895                 {
    896                     SLsmg_set_color(slang_assoc[*attr++]);
    897                     SLsmg_write_char(*chars++ & 0x7f);
    898                 }
    899                 else
    900                 {
    901                     if(fgcolor == CUCUL_COLOR_BLACK)
    902                         fgcolor = CUCUL_COLOR_WHITE;
    903                     else if(fgcolor == CUCUL_COLOR_WHITE
    904                              || fgcolor <= CUCUL_COLOR_LIGHTGRAY)
    905                         fgcolor = CUCUL_COLOR_BLACK;
    906                     else
    907                         fgcolor = CUCUL_COLOR_WHITE;
    908                     SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]);
    909                     SLsmg_write_char(' ');
    910                     chars++;
    911                     attr++;
    912                 }
    913 #else
    914                 SLsmg_set_color(*attr++);
    915                 SLsmg_write_char(*chars++ & 0x7f);
    916 #endif
    917             }
    918         }
    919         SLsmg_refresh();
    920     }
    921     else
    922 #endif
    923 #if defined(USE_NCURSES)
    924     if(kk->driver == CACA_DRIVER_NCURSES)
    925     {
    926         int x, y;
    927         uint8_t *attr = kk->qq->attr;
    928         uint32_t *chars = kk->qq->chars;
    929         for(y = 0; y < (int)kk->qq->height; y++)
    930         {
    931             move(y, 0);
    932             for(x = kk->qq->width; x--; )
    933             {
    934                 attrset(kk->ncurses.attr[*attr++]);
    935                 addch(*chars++ & 0x7f);
    936             }
    937         }
    938         refresh();
    939     }
    940     else
    941 #endif
    942 #if defined(USE_CONIO)
    943     if(kk->driver == CACA_DRIVER_CONIO)
    944     {
    945         int n;
    946         char *screen = kk->conio.screen;
    947         uint8_t *attr = kk->qq->attr;
    948         uint32_t *chars = kk->qq->chars;
    949         for(n = kk->qq->height * kk->qq->width; n--; )
    950         {
    951             *screen++ = *chars++ & 0x7f;
    952             *screen++ = *attr++;
    953         }
    954 #   if defined(SCREENUPDATE_IN_PC_H)
    955         ScreenUpdate(kk->conio.screen);
    956 #   else
    957         /* FIXME */
    958 #   endif
    959     }
    960     else
    961 #endif
    962 #if defined(USE_X11)
    963     if(kk->driver == CACA_DRIVER_X11)
    964     {
    965         unsigned int x, y, len;
    966 
    967         /* First draw the background colours. Splitting the process in two
    968          * loops like this is actually slightly faster. */
    969         for(y = 0; y < kk->qq->height; y++)
    970         {
    971             for(x = 0; x < kk->qq->width; x += len)
    972             {
    973                 uint8_t *attr = kk->qq->attr + x + y * kk->qq->width;
    974 
    975                 len = 1;
    976                 while(x + len < kk->qq->width
    977                        && (attr[len] >> 4) == (attr[0] >> 4))
    978                     len++;
    979 
    980                 XSetForeground(kk->x11.dpy, kk->x11.gc,
    981                                kk->x11.colors[attr[0] >> 4]);
    982                 XFillRectangle(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc,
    983                                x * kk->x11.font_width, y * kk->x11.font_height,
    984                                len * kk->x11.font_width, kk->x11.font_height);
    985             }
    986         }
    987 
    988         /* Then print the foreground characters */
    989         for(y = 0; y < kk->qq->height; y++)
    990         {
    991             for(x = 0; x < kk->qq->width; x += len)
    992             {
    993                 char buffer[BUFSIZ]; /* FIXME: use a smaller buffer */
    994                 uint32_t *chars = kk->qq->chars + x + y * kk->qq->width;
    995                 uint8_t *attr = kk->qq->attr + x + y * kk->qq->width;
    996 
    997                 len = 1;
    998 
    999                 /* Skip spaces */
    1000                 if(chars[0] == ' ')
    1001                     continue;
    1002 
    1003                 buffer[0] = chars[0] & 0x7f;
    1004 
    1005                 while(x + len < kk->qq->width
    1006                        && (attr[len] & 0xf) == (attr[0] & 0xf))
    1007                 {
    1008                     buffer[len] = chars[len] & 0x7f;
    1009                     len++;
    1010                 }
    1011 
    1012                 XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[attr[0] & 0xf]);
    1013                 XDrawString(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc,
    1014                             x * kk->x11.font_width,
    1015                             (y + 1) * kk->x11.font_height - kk->x11.font_offset,
    1016                             buffer, len);
    1017             }
    1018         }
    1019 
    1020         XCopyArea(kk->x11.dpy, kk->x11.pixmap, kk->x11.window, kk->x11.gc, 0, 0,
    1021                   kk->qq->width * kk->x11.font_width, kk->qq->height * kk->x11.font_height,
    1022                   0, 0);
    1023         XFlush(kk->x11.dpy);
    1024     }
    1025     else
    1026 #endif
    1027 #if defined(USE_WIN32)
    1028     if(kk->driver == CACA_DRIVER_WIN32)
    1029     {
    1030         COORD size, pos;
    1031         SMALL_RECT rect;
    1032         unsigned int i;
    1033 
    1034         /* Render everything to our back buffer */
    1035         for(i = 0; i < kk->qq->width * kk->qq->height; i++)
    1036         {
    1037             kk->win32.buffer[i].Char.AsciiChar = kk->qq->chars[i] & 0x7f;
    1038             kk->win32.buffer[i].Attributes =
    1039                     win32_fg_palette[kk->qq->attr[i] & 0xf]
    1040                      | win32_bg_palette[kk->qq->attr[i] >> 4];
    1041         }
    1042 
    1043         /* Blit the back buffer to the front buffer */
    1044         size.X = kk->qq->width;
    1045         size.Y = kk->qq->height;
    1046         pos.X = pos.Y = 0;
    1047         rect.Left = rect.Top = 0;
    1048         rect.Right = kk->qq->width - 1;
    1049         rect.Bottom = kk->qq->height - 1;
    1050         WriteConsoleOutput(kk->win32.front, kk->win32.buffer, size, pos, &rect);
    1051     }
    1052     else
    1053 #endif
    1054 #if defined(USE_GL)
    1055     if(kk->driver == CACA_DRIVER_GL)
    1056     {
    1057         unsigned int x, y, line;
    1058 
    1059         glClear(GL_COLOR_BUFFER_BIT);
    1060 
    1061         line = 0;
    1062         for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
    1063         {
    1064             uint8_t *attr = kk->qq->attr + line * kk->qq->width;
    1065 
    1066             for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
    1067             {
    1068                 glDisable(GL_TEXTURE_2D);
    1069                 glColor4bv(gl_bgpal[attr[0] >> 4]);
     254                char ch = *chars & 0x7f;
     255
     256                /* FIXME: check ch bounds */
     257                glBindTexture(GL_TEXTURE_2D, kk->gl.id[ch - 32]);
     258                glColor4bv(gl_bgpal[attr[0] & 0xf]);
    1070259                glBegin(GL_QUADS);
     260                    glTexCoord2f(0, kk->gl.sh);
    1071261                    glVertex2f(x, y);
     262                    glTexCoord2f(kk->gl.sw, kk->gl.sh);
    1072263                    glVertex2f(x + kk->gl.font_width, y);
     264                    glTexCoord2f(kk->gl.sw, 0);
    1073265                    glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height);
     266                    glTexCoord2f(0, 0);
    1074267                    glVertex2f(x, y + kk->gl.font_height);
    1075268                glEnd();
    1076 
    1077                 attr++;
    1078269            }
    1079270
    1080             line++;
     271            attr++;
     272            chars++;
    1081273        }
    1082 
    1083         /* 2nd pass, avoids changing render state too much */
    1084         glEnable(GL_BLEND);
    1085         glEnable(GL_TEXTURE_2D);
    1086         glBlendFunc(GL_ONE, GL_ONE);
    1087 
    1088         line = 0;
    1089         for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
    1090         {
    1091             uint8_t *attr = kk->qq->attr + line * kk->qq->width;
    1092             uint32_t *chars = kk->qq->chars + line * kk->qq->width;
    1093 
    1094             for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
    1095             {
    1096                 if(*chars != (uint32_t)' ')
    1097                 {
    1098                     char ch = *chars & 0x7f;
    1099 
    1100                     /* FIXME: check ch bounds */
    1101                     glBindTexture(GL_TEXTURE_2D, kk->gl.id[ch - 32]);
    1102                     glColor4bv(gl_bgpal[attr[0] & 0xf]);
    1103                     glBegin(GL_QUADS);
    1104                         glTexCoord2f(0, kk->gl.sh);
    1105                         glVertex2f(x, y);
    1106                         glTexCoord2f(kk->gl.sw, kk->gl.sh);
    1107                         glVertex2f(x + kk->gl.font_width, y);
    1108                         glTexCoord2f(kk->gl.sw, 0);
    1109                         glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height);
    1110                         glTexCoord2f(0, 0);
    1111                         glVertex2f(x, y + kk->gl.font_height);
    1112                     glEnd();
    1113                 }
    1114 
    1115                 attr++;
    1116                 chars++;
    1117             }
    1118             line++;
    1119         }
    1120         glDisable(GL_BLEND);
    1121         glDisable(GL_TEXTURE_2D);
    1122 
    1123         glutMainLoopEvent();
    1124         glutSwapBuffers();
    1125         glutPostRedisplay();
    1126     }
    1127     else
    1128 #endif
    1129     {
    1130         /* Dummy */
    1131     }
    1132 
    1133     /* FIXME handle this somewhere else */
    1134     if(kk->resize)
    1135     {
    1136         kk->resize = 0;
    1137         caca_handle_resize(kk);
    1138     }
    1139 
    1140     /* Wait until kk->delay + time of last call */
    1141     ticks += _caca_getticks(&kk->timer);
    1142     for(ticks += _caca_getticks(&kk->timer);
    1143         ticks + IDLE_USEC < (int)kk->delay;
    1144         ticks += _caca_getticks(&kk->timer))
    1145     {
    1146         _caca_sleep(IDLE_USEC);
    1147     }
    1148 
    1149     /* Update the sliding mean of the render time */
    1150     kk->rendertime = (7 * kk->rendertime + ticks) / 8;
    1151 
    1152     kk->lastticks = ticks - kk->delay;
    1153 
    1154     /* If we drifted too much, it's bad, bad, bad. */
    1155     if(kk->lastticks > (int)kk->delay)
    1156         kk->lastticks = 0;
    1157 }
    1158 
    1159 /*
    1160  * XXX: following functions are local
    1161  */
    1162 
    1163 static void caca_handle_resize(caca_t *kk)
     274        line++;
     275    }
     276    glDisable(GL_BLEND);
     277    glDisable(GL_TEXTURE_2D);
     278
     279    glutMainLoopEvent();
     280    glutSwapBuffers();
     281    glutPostRedisplay();
     282}
     283
     284void gl_handle_resize(caca_t *kk)
    1164285{
    1165286    unsigned int new_width, new_height;
     
    1168289    new_height = kk->qq->height;
    1169290
    1170 #if defined(USE_SLANG)
    1171     if(kk->driver == CACA_DRIVER_SLANG)
    1172     {
    1173         SLtt_get_screen_size();
    1174         new_width = SLtt_Screen_Cols;
    1175         new_height = SLtt_Screen_Rows;
    1176 
    1177         if(new_width != kk->qq->width || new_height != kk->qq->height)
    1178             SLsmg_reinit_smg();
    1179     }
    1180     else
    1181 #endif
    1182 #if defined(USE_NCURSES)
    1183     if(kk->driver == CACA_DRIVER_NCURSES)
    1184     {
    1185         struct winsize size;
    1186 
    1187         if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0)
    1188         {
    1189             new_width = size.ws_col;
    1190             new_height = size.ws_row;
    1191 #if defined(HAVE_RESIZE_TERM)
    1192             resize_term(new_height, new_width);
    1193 #else
    1194             resizeterm(new_height, new_width);
    1195 #endif
    1196             wrefresh(curscr);
    1197         }
    1198     }
    1199     else
    1200 #endif
    1201 #if defined(USE_CONIO)
    1202     if(kk->driver == CACA_DRIVER_CONIO)
    1203     {
    1204         /* Nothing to do here. */
    1205     }
    1206     else
    1207 #endif
    1208 #if defined(USE_X11)
    1209     if(kk->driver == CACA_DRIVER_X11)
    1210     {
    1211         Pixmap new_pixmap;
    1212 
    1213         new_width = kk->x11.new_width;
    1214         new_height = kk->x11.new_height;
    1215 
    1216         new_pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window,
    1217                                    kk->qq->width * kk->x11.font_width,
    1218                                    kk->qq->height * kk->x11.font_height,
    1219                                    DefaultDepth(kk->x11.dpy,
    1220                                                 DefaultScreen(kk->x11.dpy)));
    1221         XCopyArea(kk->x11.dpy, kk->x11.pixmap, new_pixmap, kk->x11.gc, 0, 0,
    1222                   kk->qq->width * kk->x11.font_width,
    1223                   kk->qq->height * kk->x11.font_height, 0, 0);
    1224         XFreePixmap(kk->x11.dpy, kk->x11.pixmap);
    1225         kk->x11.pixmap = new_pixmap;
    1226     }
    1227     else
    1228 #endif
    1229 #if defined(USE_WIN32)
    1230     if(kk->driver == CACA_DRIVER_WIN32)
    1231     {
    1232         /* Nothing to do here. */
    1233     }
    1234     else
    1235 #endif
    1236 #if defined(USE_GL)
    1237     if(kk->driver == CACA_DRIVER_GL)
    1238     {
    1239         kk->gl.width = kk->gl.new_width;
    1240         kk->gl.height = kk->gl.new_height;
    1241 
    1242         new_width = kk->gl.width / kk->gl.font_width;
    1243         new_height = (kk->gl.height / kk->gl.font_height) + 1;
    1244 
    1245         glMatrixMode(GL_PROJECTION);
    1246         glPushMatrix();
    1247         glLoadIdentity();
    1248 
    1249         glViewport(0, 0, kk->gl.width, kk->gl.height);
    1250         gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
    1251         glMatrixMode(GL_MODELVIEW);
    1252     }
    1253     else
    1254 #endif
    1255     {
    1256         /* Dummy */
    1257     }
    1258 
    1259     /* Tell libcucul we changed size */
    1260     if(new_width != kk->qq->width || new_height != kk->qq->height)
    1261         cucul_set_size(kk->qq, new_width, new_height);
    1262 }
    1263 
    1264 #if defined(USE_SLANG)
    1265 static void slang_init_palette(void)
    1266 {
    1267     /* See SLang ref., 5.4.4. */
    1268     static char *slang_colors[16] =
    1269     {
    1270         /* Standard colours */
    1271         "black",
    1272         "blue",
    1273         "green",
    1274         "cyan",
    1275         "red",
    1276         "magenta",
    1277         "brown",
    1278         "lightgray",
    1279         /* Bright colours */
    1280         "gray",
    1281         "brightblue",
    1282         "brightgreen",
    1283         "brightcyan",
    1284         "brightred",
    1285         "brightmagenta",
    1286         "yellow",
    1287         "white",
    1288     };
    1289 
    1290 #if defined(OPTIMISE_SLANG_PALETTE)
    1291     int i;
    1292 
    1293     for(i = 0; i < 16 * 16; i++)
    1294         SLtt_set_color(i, NULL, slang_colors[slang_palette[i * 2]],
    1295                                 slang_colors[slang_palette[i * 2 + 1]]);
    1296 #else
    1297     int fg, bg;
    1298 
    1299     for(bg = 0; bg < 16; bg++)
    1300         for(fg = 0; fg < 16; fg++)
    1301         {
    1302             int i = fg + 16 * bg;
    1303             SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]);
    1304         }
    1305 #endif
    1306 }
    1307 #endif /* USE_SLANG */
    1308 
    1309 #if defined(USE_X11)
    1310 static int x11_error_handler(Display *dpy, XErrorEvent *event)
    1311 {
    1312     /* Ignore the error */
    1313     return 0;
    1314 }
    1315 #endif
    1316 
    1317 #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
    1318 static RETSIGTYPE sigwinch_handler(int sig)
    1319 {
    1320     sigwinch_kk->resize_event = 1;
    1321 
    1322     signal(SIGWINCH, sigwinch_handler);;
    1323 }
    1324 #endif
    1325 
    1326 #if defined(USE_GL)
     291    kk->gl.width = kk->gl.new_width;
     292    kk->gl.height = kk->gl.new_height;
     293
     294    new_width = kk->gl.width / kk->gl.font_width;
     295    new_height = (kk->gl.height / kk->gl.font_height) + 1;
     296
     297    glMatrixMode(GL_PROJECTION);
     298    glPushMatrix();
     299    glLoadIdentity();
     300
     301    glViewport(0, 0, kk->gl.width, kk->gl.height);
     302    gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
     303    glMatrixMode(GL_MODELVIEW);
     304}
     305
     306/*
     307 * XXX: following functions are local
     308 */
     309
    1327310static void gl_handle_keyboard(unsigned char key, int x, int y)
    1328311{
     
    1374357    kk->gl.mouse_changed = 1;
    1375358}
    1376 #endif
    1377 
     359
     360/*
     361 * Driver initialisation
     362 */
     363
     364void gl_init_driver(caca_t *kk)
     365{
     366    kk->driver.driver = CACA_DRIVER_GL;
     367
     368    kk->driver.init_graphics = gl_init_graphics;
     369    kk->driver.end_graphics = gl_end_graphics;
     370    kk->driver.set_window_title = gl_set_window_title;
     371    kk->driver.get_window_width = gl_get_window_width;
     372    kk->driver.get_window_height = gl_get_window_height;
     373    kk->driver.display = gl_display;
     374    kk->driver.handle_resize = gl_handle_resize;
     375}
     376
     377#endif /* USE_GL */
     378
  • libcaca/trunk/caca/driver_ncurses.c

    r537 r539  
    2020#include "config.h"
    2121
    22 #if defined(USE_SLANG)
    23 #   if defined(HAVE_SLANG_SLANG_H)
    24 #       include <slang/slang.h>
    25 #   else
    26 #       include <slang.h>
    27 #   endif
    28 #endif
    29 #if defined(USE_NCURSES)
    30 #   if defined(HAVE_NCURSES_H)
    31 #       include <ncurses.h>
    32 #   else
    33 #       include <curses.h>
    34 #   endif
    35 #endif
    36 #if defined(USE_CONIO)
    37 #   include <conio.h>
    38 #   if defined(SCREENUPDATE_IN_PC_H)
    39 #       include <pc.h>
    40 #   endif
    41 #endif
    42 #if defined(USE_X11)
    43 #   include <X11/Xlib.h>
    44 #   if defined(HAVE_X11_XKBLIB_H)
    45 #       include <X11/XKBlib.h>
    46 #   endif
    47 #endif
    48 #if defined(USE_WIN32)
    49 #   include <windows.h>
    50 #endif
    51 #if defined(USE_GL)
    52 #   include <GL/gl.h>
    53 #   include <GL/glut.h>
    54 #   include <GL/freeglut_ext.h>
    55 #endif
    5622#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME)
    5723#   include <inttypes.h>
     
    6127#endif
    6228
     29#if defined(USE_NCURSES)
     30
     31#if defined(HAVE_NCURSES_H)
     32#   include <ncurses.h>
     33#else
     34#   include <curses.h>
     35#endif
     36
    6337#include <stdio.h> /* BUFSIZ */
    6438#include <string.h>
     
    8155#include "cucul_internals.h"
    8256
    83 /*
    84  * Global variables
    85  */
    86 
    87 #if defined(USE_SLANG)
    88 /* Tables generated by test/optipal.c */
    89 static int const slang_palette[2*16*16] =
    90 {
    91      1,  0,   2,  0,   3,  0,   4,  0,   5,  0,   6,  0,   7,  0,   8,  0,
    92      9,  0,  10,  0,  11,  0,  12,  0,  13,  0,  14,  0,  15,  0,   0,  8,
    93      8,  7,   7,  8,  15,  7,   7, 15,  15,  9,   9, 15,   1,  9,   9,  1,
    94      7,  9,   9,  7,   8,  1,   1,  8,   0,  1,  15, 10,  10, 15,   2, 10,
    95     10,  2,   7, 10,  10,  7,   8,  2,   2,  8,   0,  2,  15, 11,  11, 15,
    96      3, 11,  11,  3,   7, 11,  11,  7,   8,  3,   3,  8,   0,  3,  15, 12,
    97     12, 15,   4, 12,  12,  4,   7, 12,  12,  7,   8,  4,   4,  8,   0,  4,
    98     15, 13,  13, 15,   5, 13,  13,  5,   7, 13,  13,  7,   8,  5,   5,  8,
    99      0,  5,  15, 14,  14, 15,   6, 14,  14,  6,   7, 14,  14,  7,   8,  6,
    100      6,  8,   0,  6,   4,  6,   6,  4,  12, 14,  14, 12,   6,  2,   2,  6,
    101     14, 10,  10, 14,   2,  3,   3,  2,  10, 11,  11, 10,   3,  1,   1,  3,
    102     11,  9,   9, 11,   1,  5,   5,  1,   9, 13,  13,  9,   5,  4,   4,  5,
    103     13, 12,  12, 13,   4, 14,   6, 12,  12,  6,  14,  4,   6, 10,   2, 14,
    104     14,  2,  10,  6,   2, 11,   3, 10,  10,  3,  11,  2,   3,  9,   1, 11,
    105     11,  1,   9,  3,   1, 13,   5,  9,   9,  5,  13,  1,   5, 12,   4, 13,
    106     13,  4,  12,  5,   0,  7,   0, 15,  15,  8,   8, 15,  15,  1,   7,  1,
    107      1,  6,   2,  5,   3,  4,   4,  3,   5,  2,   6,  1,   0,  0,   1,  1,
    108      9,  6,  10,  5,  11,  4,  12,  3,  13,  2,  14,  1,   2,  2,   3,  3,
    109      4,  4,   5,  5,   6,  6,   7,  7,  14,  9,   1, 15,   8,  9,   8,  8,
    110      9,  9,   1,  7,   0,  9,   9,  8,   6,  9,  13, 10,   2, 15,   8, 10,
    111      7,  2,  15,  2,   2,  7,   0, 10,  10,  8,   5, 10,  12, 11,   3, 15,
    112      8, 11,   7,  3,  15,  3,   3,  7,   0, 11,  11,  8,   4, 11,  11, 12,
    113      4, 15,   8, 12,   7,  4,  15,  4,   4,  7,   0, 12,  12,  8,   3, 12,
    114     10, 13,   5, 15,   8, 13,   7,  5,  15,  5,   5,  7,   0, 13,  13,  8,
    115      2, 13,   9, 14,   6, 15,   8, 14,   7,  6,  15,  6,   6,  7,   0, 14,
    116     14,  8,   1, 14,   5,  6,   2,  4,  13, 14,  10, 12,   4,  2,   3,  6,
    117     12, 10,  11, 14,   6,  3,   1,  2,  14, 11,   9, 10,   2,  1,   5,  3,
    118     10,  9,  13, 11,   3,  5,   4,  1,  11, 13,  12,  9,   1,  4,   6,  5,
    119      9, 12,  14, 13,   5, 14,   2, 12,  13,  6,  10,  4,   4, 10,   3, 14,
    120     12,  2,  11,  6,   6, 11,   1, 10,  14,  3,   9,  2,   2,  9,   5, 11,
    121     10,  1,  13,  3,   3, 13,   4,  9,  11,  5,  12,  1,   1, 12,   6, 13,
    122      9,  4,  14,  5,  10, 10,  11, 11,  12, 12,  13, 13,  14, 14,  15, 15,
    123 };
    124 
    125 static int const slang_assoc[16*16] =
    126 {
    127     134, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
    128     28, 135, 214, 86, 219, 91, 133, 127, 26, 23, 240, 112, 245, 117, 141, 126,
    129     37, 211, 142, 83, 206, 132, 78, 160, 35, 237, 32, 109, 232, 140, 104, 161,
    130     46, 87, 82, 143, 131, 215, 210, 169, 44, 113, 108, 41, 139, 241, 236, 170,
    131     55, 222, 203, 130, 144, 94, 75, 178, 53, 248, 229, 138, 50, 120, 101, 179,
    132     64, 90, 129, 218, 95, 145, 223, 187, 62, 116, 137, 244, 121, 59, 249, 188,
    133     73, 128, 79, 207, 74, 202, 146, 196, 71, 136, 105, 233, 100, 228, 68, 197,
    134     122, 153, 162, 171, 180, 189, 198, 147, 16, 25, 34, 43, 52, 61, 70, 18,
    135     15, 27, 36, 45, 54, 63, 72, 17, 151, 155, 164, 173, 182, 191, 200, 124,
    136     154, 22, 238, 110, 243, 115, 156, 24, 150, 152, 216, 88, 221, 93, 148, 20,
    137     163, 235, 31, 107, 230, 165, 102, 33, 159, 213, 250, 85, 208, 157, 80, 29,
    138     172, 111, 106, 40, 174, 239, 234, 42, 168, 89, 84, 251, 166, 217, 212, 38,
    139     181, 246, 227, 183, 49, 118, 99, 51, 177, 224, 205, 175, 252, 96, 77, 47,
    140     190, 114, 192, 242, 119, 58, 247, 60, 186, 92, 184, 220, 97, 253, 225, 56,
    141     199, 201, 103, 231, 98, 226, 67, 69, 195, 193, 81, 209, 76, 204, 254, 65,
    142     123, 149, 158, 167, 176, 185, 194, 19, 125, 21, 30, 39, 48, 57, 66, 255,
    143 };
    144 #endif
    145 
    146 #if defined(USE_WIN32)
    147 static int const win32_fg_palette[] =
    148 {
    149     0,
    150     FOREGROUND_BLUE,
    151     FOREGROUND_GREEN,
    152     FOREGROUND_GREEN | FOREGROUND_BLUE,
    153     FOREGROUND_RED,
    154     FOREGROUND_RED | FOREGROUND_BLUE,
    155     FOREGROUND_RED | FOREGROUND_GREEN,
    156     FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
    157     FOREGROUND_INTENSITY,
    158     FOREGROUND_INTENSITY | FOREGROUND_BLUE,
    159     FOREGROUND_INTENSITY | FOREGROUND_GREEN,
    160     FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE,
    161     FOREGROUND_INTENSITY | FOREGROUND_RED,
    162     FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE,
    163     FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN,
    164     FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
    165 };
    166 
    167 static int const win32_bg_palette[] =
    168 {
    169     0,
    170     BACKGROUND_BLUE,
    171     BACKGROUND_GREEN,
    172     BACKGROUND_GREEN | BACKGROUND_BLUE,
    173     BACKGROUND_RED,
    174     BACKGROUND_RED | BACKGROUND_BLUE,
    175     BACKGROUND_RED | BACKGROUND_GREEN,
    176     BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
    177     BACKGROUND_INTENSITY,
    178     BACKGROUND_INTENSITY | BACKGROUND_BLUE,
    179     BACKGROUND_INTENSITY | BACKGROUND_GREEN,
    180     BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE,
    181     BACKGROUND_INTENSITY | BACKGROUND_RED,
    182     BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE,
    183     BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN,
    184     BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
    185 };
    186 #endif
    187 
    188 #if defined(USE_GL)
    189 /* Ok, I just suck. */
    190 static GLbyte const gl_bgpal[][4] =
    191 {
    192     { 0x00, 0x00, 0x00, 0x7f },
    193     { 0x00, 0x00, 0x3f, 0x7f },
    194     { 0x00, 0x3f, 0x00, 0x7f },
    195     { 0x00, 0x3f, 0x3f, 0x7f },
    196     { 0x3f, 0x00, 0x00, 0x7f },
    197     { 0x3f, 0x00, 0x3f, 0x7f },
    198     { 0x3f, 0x3f, 0x00, 0x7f },
    199     { 0x3f, 0x3f, 0x3f, 0x7f },
    200     // + intensity
    201     { 0x00, 0x00, 0x00, 0x7f },
    202     { 0x00, 0x00, 0x7f, 0x7f },
    203     { 0x00, 0x7f, 0x00, 0x7f },
    204     { 0x00, 0x7f, 0x7f, 0x7f },
    205     { 0x7f, 0x00, 0x00, 0x7f },
    206     { 0x7f, 0x00, 0x7f, 0x7f },
    207     { 0x7f, 0x7f, 0x00, 0x7f },
    208     { 0x7f, 0x7f, 0x7f, 0x7f }
    209 };
    210 
    211 static caca_t *gl_kk; /* FIXME: we ought to get rid of this */
    212 #endif
     57int ncurses_init_graphics(caca_t *);
     58int ncurses_end_graphics(caca_t *);
     59int ncurses_set_window_title(caca_t *, char const *);
     60unsigned int ncurses_get_window_width(caca_t *);
     61unsigned int ncurses_get_window_height(caca_t *);
     62void ncurses_display(caca_t *);
     63void ncurses_handle_resize(caca_t *);
    21364
    21465/*
    21566 * Local functions
    21667 */
    217 static void caca_handle_resize(caca_t *kk);
    218 
    219 #if defined(USE_SLANG)
    220 static void slang_init_palette(void);
    221 #endif
    222 
    223 #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
     68#if defined(HAVE_SIGNAL)
    22469static RETSIGTYPE sigwinch_handler(int);
    22570static caca_t *sigwinch_kk; /* FIXME: we ought to get rid of this */
    22671#endif
    22772
    228 #if defined(USE_X11)
    229 static int x11_error_handler(Display *, XErrorEvent *);
    230 #endif
    231 
    232 #if defined(USE_GL)
    233 static void gl_handle_keyboard(unsigned char, int, int);
    234 static void gl_handle_special_key(int, int, int);
    235 static void gl_handle_reshape(int, int);
    236 static void gl_handle_mouse(int, int, int, int);
    237 static void gl_handle_mouse_motion(int, int);
    238 #endif
    239 
    240 #if !defined(_DOXYGEN_SKIP_ME)
    241 int _caca_init_graphics(caca_t *kk)
    242 {
    243 #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
     73int ncurses_init_graphics(caca_t *kk)
     74{
     75    static int curses_colors[] =
     76    {
     77        /* Standard curses colours */
     78        COLOR_BLACK,
     79        COLOR_BLUE,
     80        COLOR_GREEN,
     81        COLOR_CYAN,
     82        COLOR_RED,
     83        COLOR_MAGENTA,
     84        COLOR_YELLOW,
     85        COLOR_WHITE,
     86        /* Extra values for xterm-16color */
     87        COLOR_BLACK + 8,
     88        COLOR_BLUE + 8,
     89        COLOR_GREEN + 8,
     90        COLOR_CYAN + 8,
     91        COLOR_RED + 8,
     92        COLOR_MAGENTA + 8,
     93        COLOR_YELLOW + 8,
     94        COLOR_WHITE + 8
     95    };
     96
     97    mmask_t newmask;
     98    int fg, bg, max;
     99
     100#if defined(HAVE_SIGNAL)
    244101    sigwinch_kk = kk;
    245102    signal(SIGWINCH, sigwinch_handler);
    246103#endif
    247104
    248 #if defined(USE_SLANG)
    249     if(kk->driver == CACA_DRIVER_SLANG)
     105    initscr();
     106    keypad(stdscr, TRUE);
     107    nonl();
     108    raw();
     109    noecho();
     110    nodelay(stdscr, TRUE);
     111    curs_set(0);
     112
     113    /* Activate mouse */
     114    newmask = REPORT_MOUSE_POSITION | ALL_MOUSE_EVENTS;
     115    mousemask(newmask, &kk->ncurses.oldmask);
     116    mouseinterval(-1); /* No click emulation */
     117
     118    /* Set the escape delay to a ridiculously low value */
     119    ESCDELAY = 10;
     120
     121    /* Activate colour */
     122    start_color();
     123
     124    /* If COLORS == 16, it means the terminal supports full bright colours
     125     * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
     126     * we can build 16*16 colour pairs.
     127     * If COLORS == 8, it means the terminal does not know about bright
     128     * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
     129     * and \e[5m). We can only build 8*8 colour pairs. */
     130    max = COLORS >= 16 ? 16 : 8;
     131
     132    for(bg = 0; bg < max; bg++)
     133        for(fg = 0; fg < max; fg++)
     134        {
     135            /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
     136             * is light gray on black. Some terminals don't like this
     137             * colour pair to be redefined. */
     138            int col = ((max + 7 - fg) % max) + max * bg;
     139            init_pair(col, curses_colors[fg], curses_colors[bg]);
     140            kk->ncurses.attr[fg + 16 * bg] = COLOR_PAIR(col);
     141
     142            if(max == 8)
     143            {
     144                /* Bright fg on simple bg */
     145                kk->ncurses.attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
     146                /* Simple fg on bright bg */
     147                kk->ncurses.attr[fg + 16 * (bg + 8)] = A_BLINK
     148                                                    | COLOR_PAIR(col);
     149                /* Bright fg on bright bg */
     150                kk->ncurses.attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
     151                                                        | COLOR_PAIR(col);
     152            }
     153        }
     154
     155    cucul_set_size(kk->qq, COLS, LINES);
     156
     157    return 0;
     158}
     159
     160int ncurses_end_graphics(caca_t *kk)
     161{
     162    mousemask(kk->ncurses.oldmask, NULL);
     163    curs_set(1);
     164    noraw();
     165    endwin();
     166
     167    return 0;
     168}
     169
     170int ncurses_set_window_title(caca_t *kk, char const *title)
     171{
     172    return 0;
     173}
     174
     175unsigned int ncurses_get_window_width(caca_t *kk)
     176{
     177    /* Fallback to a 6x10 font */
     178    return kk->qq->width * 6;
     179}
     180
     181unsigned int ncurses_get_window_height(caca_t *kk)
     182{
     183    /* Fallback to a 6x10 font */
     184    return kk->qq->height * 10;
     185}
     186
     187void ncurses_display(caca_t *kk)
     188{
     189    int x, y;
     190    uint8_t *attr = kk->qq->attr;
     191    uint32_t *chars = kk->qq->chars;
     192    for(y = 0; y < (int)kk->qq->height; y++)
    250193    {
    251         slang_init_palette();
    252 
    253         /* Disable alt charset support so that we get a chance to have all
    254          * 256 colour pairs */
    255         SLtt_Has_Alt_Charset = 0;
    256 
    257         cucul_set_size(kk->qq, SLtt_Screen_Cols, SLtt_Screen_Rows);
    258     }
    259     else
    260 #endif
    261 #if defined(USE_NCURSES)
    262     if(kk->driver == CACA_DRIVER_NCURSES)
    263     {
    264         static int curses_colors[] =
     194        move(y, 0);
     195        for(x = kk->qq->width; x--; )
    265196        {
    266             /* Standard curses colours */
    267             COLOR_BLACK,
    268             COLOR_BLUE,
    269             COLOR_GREEN,
    270             COLOR_CYAN,
    271             COLOR_RED,
    272             COLOR_MAGENTA,
    273             COLOR_YELLOW,
    274             COLOR_WHITE,
    275             /* Extra values for xterm-16color */
    276             COLOR_BLACK + 8,
    277             COLOR_BLUE + 8,
    278             COLOR_GREEN + 8,
    279             COLOR_CYAN + 8,
    280             COLOR_RED + 8,
    281             COLOR_MAGENTA + 8,
    282             COLOR_YELLOW + 8,
    283             COLOR_WHITE + 8
    284         };
    285 
    286         int fg, bg, max;
    287 
    288         /* Activate colour */
    289         start_color();
    290 
    291         /* If COLORS == 16, it means the terminal supports full bright colours
    292          * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
    293          * we can build 16*16 colour pairs.
    294          * If COLORS == 8, it means the terminal does not know about bright
    295          * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
    296          * and \e[5m). We can only build 8*8 colour pairs. */
    297         max = COLORS >= 16 ? 16 : 8;
    298 
    299         for(bg = 0; bg < max; bg++)
    300             for(fg = 0; fg < max; fg++)
    301             {
    302                 /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
    303                  * is light gray on black. Some terminals don't like this
    304                  * colour pair to be redefined. */
    305                 int col = ((max + 7 - fg) % max) + max * bg;
    306                 init_pair(col, curses_colors[fg], curses_colors[bg]);
    307                 kk->ncurses.attr[fg + 16 * bg] = COLOR_PAIR(col);
    308 
    309                 if(max == 8)
    310                 {
    311                     /* Bright fg on simple bg */
    312                     kk->ncurses.attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
    313                     /* Simple fg on bright bg */
    314                     kk->ncurses.attr[fg + 16 * (bg + 8)] = A_BLINK
    315                                                         | COLOR_PAIR(col);
    316                     /* Bright fg on bright bg */
    317                     kk->ncurses.attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
    318                                                             | COLOR_PAIR(col);
    319                 }
    320             }
    321 
    322         cucul_set_size(kk->qq, COLS, LINES);
    323     }
    324     else
    325 #endif
    326 #if defined(USE_CONIO)
    327     if(kk->driver == CACA_DRIVER_CONIO)
    328     {
    329         gettextinfo(&kk->conio.ti);
    330         kk->conio.screen = malloc(2 * kk->conio.ti.screenwidth
    331                                 * kk->conio.ti.screenheight * sizeof(char));
    332         if(kk->conio.screen == NULL)
    333             return -1;
    334 #   if defined(SCREENUPDATE_IN_PC_H)
    335         ScreenRetrieve(kk->conio.screen);
    336 #   else
    337         /* FIXME */
    338 #   endif
    339         cucul_set_size(kk->qq, kk->conio.ti.screenwidth,
    340                                kk->conio.ti.screenheight);
    341     }
    342     else
    343 #endif
    344 #if defined(USE_X11)
    345     if(kk->driver == CACA_DRIVER_X11)
    346     {
    347         static int const x11_palette[] =
    348         {
    349             /* Standard curses colours */
    350             0x0,    0x0,    0x0,
    351             0x0,    0x0,    0x8000,
    352             0x0,    0x8000, 0x0,
    353             0x0,    0x8000, 0x8000,
    354             0x8000, 0x0,    0x0,
    355             0x8000, 0x0,    0x8000,
    356             0x8000, 0x8000, 0x0,
    357             0x8000, 0x8000, 0x8000,
    358             /* Extra values for xterm-16color */
    359             0x4000, 0x4000, 0x4000,
    360             0x4000, 0x4000, 0xffff,
    361             0x4000, 0xffff, 0x4000,
    362             0x4000, 0xffff, 0xffff,
    363             0xffff, 0x4000, 0x4000,
    364             0xffff, 0x4000, 0xffff,
    365             0xffff, 0xffff, 0x4000,
    366             0xffff, 0xffff, 0xffff,
    367         };
    368 
    369         Colormap colormap;
    370         XSetWindowAttributes x11_winattr;
    371         int (*old_error_handler)(Display *, XErrorEvent *);
    372         char const *fonts[] = { NULL, "8x13bold", "fixed" }, **parser;
    373         char const *geometry;
    374         unsigned int width = 0, height = 0;
    375         int i;
    376 
    377         geometry = getenv("CACA_GEOMETRY");
    378         if(geometry && *(geometry))
    379             sscanf(geometry, "%ux%u", &width, &height);
    380 
    381         if(width && height)
    382             cucul_set_size(kk->qq, width, height);
    383 
    384         kk->x11.dpy = XOpenDisplay(NULL);
    385         if(kk->x11.dpy == NULL)
    386             return -1;
    387 
    388         fonts[0] = getenv("CACA_FONT");
    389         if(fonts[0] && *fonts[0])
    390             parser = fonts;
    391         else
    392             parser = fonts + 1;
    393 
    394         /* Ignore font errors */
    395         old_error_handler = XSetErrorHandler(x11_error_handler);
    396 
    397         /* Parse our font list */
    398         for( ; ; parser++)
    399         {
    400             if(!*parser)
    401             {
    402                 XSetErrorHandler(old_error_handler);
    403                 XCloseDisplay(kk->x11.dpy);
    404                 return -1;
    405             }
    406 
    407             kk->x11.font = XLoadFont(kk->x11.dpy, *parser);
    408             if(!kk->x11.font)
    409                 continue;
    410 
    411             kk->x11.font_struct = XQueryFont(kk->x11.dpy, kk->x11.font);
    412             if(!kk->x11.font_struct)
    413             {
    414                 XUnloadFont(kk->x11.dpy, kk->x11.font);
    415                 continue;
    416             }
    417 
    418             break;
    419         }
    420 
    421         /* Reset the default X11 error handler */
    422         XSetErrorHandler(old_error_handler);
    423 
    424         kk->x11.font_width = kk->x11.font_struct->max_bounds.width;
    425         kk->x11.font_height = kk->x11.font_struct->max_bounds.ascent
    426                              + kk->x11.font_struct->max_bounds.descent;
    427         kk->x11.font_offset = kk->x11.font_struct->max_bounds.descent;
    428 
    429         colormap = DefaultColormap(kk->x11.dpy, DefaultScreen(kk->x11.dpy));
    430         for(i = 0; i < 16; i++)
    431         {
    432             XColor color;
    433             color.red = x11_palette[i * 3];
    434             color.green = x11_palette[i * 3 + 1];
    435             color.blue = x11_palette[i * 3 + 2];
    436             XAllocColor(kk->x11.dpy, colormap, &color);
    437             kk->x11.colors[i] = color.pixel;
    438         }
    439 
    440         x11_winattr.backing_store = Always;
    441         x11_winattr.background_pixel = kk->x11.colors[0];
    442         x11_winattr.event_mask = ExposureMask | StructureNotifyMask;
    443 
    444         kk->x11.window =
    445             XCreateWindow(kk->x11.dpy, DefaultRootWindow(kk->x11.dpy), 0, 0,
    446                           kk->qq->width * kk->x11.font_width,
    447                           kk->qq->height * kk->x11.font_height,
    448                           0, 0, InputOutput, 0,
    449                           CWBackingStore | CWBackPixel | CWEventMask,
    450                           &x11_winattr);
    451 
    452         XStoreName(kk->x11.dpy, kk->x11.window, "caca for X");
    453 
    454         XSelectInput(kk->x11.dpy, kk->x11.window, StructureNotifyMask);
    455         XMapWindow(kk->x11.dpy, kk->x11.window);
    456 
    457         kk->x11.gc = XCreateGC(kk->x11.dpy, kk->x11.window, 0, NULL);
    458         XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[15]);
    459         XSetFont(kk->x11.dpy, kk->x11.gc, kk->x11.font);
    460 
    461         for(;;)
    462         {
    463             XEvent event;
    464             XNextEvent(kk->x11.dpy, &event);
    465             if (event.type == MapNotify)
    466                 break;
    467         }
    468 
    469 #if defined(HAVE_X11_XKBLIB_H)
    470         /* Disable autorepeat */
    471         XkbSetDetectableAutoRepeat(kk->x11.dpy, True, &kk->x11.autorepeat);
    472         if(!kk->x11.autorepeat)
    473             XAutoRepeatOff(kk->x11.dpy);
    474 #endif
    475 
    476         XSelectInput(kk->x11.dpy, kk->x11.window, kk->x11.event_mask);
    477 
    478         XSync(kk->x11.dpy, False);
    479 
    480         kk->x11.pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window,
    481                                        kk->qq->width * kk->x11.font_width,
    482                                        kk->qq->height * kk->x11.font_height,
    483                                        DefaultDepth(kk->x11.dpy,
    484                                                 DefaultScreen(kk->x11.dpy)));
    485 
    486         kk->x11.new_width = kk->x11.new_height = 0;
    487     }
    488     else
    489 #endif
    490 #if defined(USE_WIN32)
    491     if(kk->driver == CACA_DRIVER_WIN32)
    492     {
    493         CONSOLE_CURSOR_INFO cci;
    494         CONSOLE_SCREEN_BUFFER_INFO csbi;
    495         COORD size;
    496 
    497         kk->win32.front =
    498             CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
    499                                       0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    500         if(!kk->win32.front || kk->win32.front == INVALID_HANDLE_VALUE)
    501             return -1;
    502 
    503         kk->win32.back =
    504             CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
    505                                       0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    506         if(!kk->win32.back || kk->win32.back == INVALID_HANDLE_VALUE)
    507             return -1;
    508 
    509         if(!GetConsoleScreenBufferInfo(kk->win32.hout, &csbi))
    510             return -1;
    511 
    512         /* Sample code to get the biggest possible window */
    513         //size = GetLargestConsoleWindowSize(kk->win32.hout);
    514         cucul_set_size(kk->qq, csbi.srWindow.Right - csbi.srWindow.Left + 1,
    515                                csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
    516         size.X = kk->qq->width;
    517         size.Y = kk->qq->height;
    518         SetConsoleScreenBufferSize(kk->win32.front, size);
    519         SetConsoleScreenBufferSize(kk->win32.back, size);
    520 
    521         SetConsoleMode(kk->win32.front, 0);
    522         SetConsoleMode(kk->win32.back, 0);
    523 
    524         GetConsoleCursorInfo(kk->win32.front, &cci);
    525         cci.dwSize = 0;
    526         cci.bVisible = FALSE;
    527         SetConsoleCursorInfo(kk->win32.front, &cci);
    528         SetConsoleCursorInfo(kk->win32.back, &cci);
    529 
    530         SetConsoleActiveScreenBuffer(kk->win32.front);
    531 
    532         kk->win32.buffer = malloc(kk->qq->width * kk->qq->height
    533                                    * sizeof(CHAR_INFO));
    534         if(kk->win32.buffer == NULL)
    535             return -1;
    536     }
    537     else
    538 #endif
    539 #if defined(USE_GL)
    540     if(kk->driver == CACA_DRIVER_GL)
    541     {
    542         char *empty_texture;
    543         char const *geometry;
    544         char *argv[2] = { "", NULL };
    545         unsigned int width = 0, height = 0;
    546         int argc = 1;
    547         int i;
    548 
    549         gl_kk = kk;
    550 
    551         geometry = getenv("CACA_GEOMETRY");
    552         if(geometry && *(geometry))
    553             sscanf(geometry, "%ux%u", &width, &height);
    554 
    555         if(width && height)
    556             cucul_set_size(kk->qq, width, height);
    557 
    558         kk->gl.font_width = 9;
    559         kk->gl.font_height = 15;
    560 
    561         kk->gl.width = kk->qq->width * kk->gl.font_width;
    562         kk->gl.height = kk->qq->height * kk->gl.font_height;
    563 
    564         kk->gl.resized = 0;
    565         kk->gl.bit = 0;
    566 
    567         kk->gl.mouse_changed = kk->gl.mouse_clicked = 0;
    568         kk->gl.mouse_button = kk->gl.mouse_state = 0;
    569 
    570         kk->gl.key = 0;
    571         kk->gl.special_key = 0;
    572 
    573         kk->gl.sw = 9.0f / 16.0f;
    574         kk->gl.sh = 15.0f / 16.0f;
    575 
    576         glutInit(&argc, argv);
    577 
    578         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    579         glutInitWindowSize(kk->gl.width, kk->gl.height);
    580         kk->gl.window = glutCreateWindow("caca for GL");
    581 
    582         gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
    583 
    584         glDisable(GL_CULL_FACE);
    585         glDisable(GL_DEPTH_TEST);
    586 
    587         glutKeyboardFunc(gl_handle_keyboard);
    588         glutSpecialFunc(gl_handle_special_key);
    589         glutReshapeFunc(gl_handle_reshape);
    590 
    591         glutMouseFunc(gl_handle_mouse);
    592         glutMotionFunc(gl_handle_mouse_motion);
    593         glutPassiveMotionFunc(gl_handle_mouse_motion);
    594 
    595         glLoadIdentity();
    596 
    597         glMatrixMode(GL_PROJECTION);
    598         glPushMatrix();
    599         glLoadIdentity();
    600         gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
    601 
    602         glMatrixMode(GL_MODELVIEW);
    603 
    604         glClear(GL_COLOR_BUFFER_BIT);
    605 
    606         empty_texture = malloc(16 * 16 * 4);
    607         if(empty_texture == NULL)
    608             return -1;
    609 
    610         memset(empty_texture, 0xff, 16 * 16 * 4);
    611         glEnable(GL_TEXTURE_2D);
    612 
    613         for(i = 0; i < 94; i++)
    614         {
    615             glGenTextures(1, (GLuint*)&kk->gl.id[i]);
    616             glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
    617             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    618             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    619             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8,
    620                          16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, empty_texture);
    621         }
    622 
    623         for(i = 0; i < 94; i++)
    624         {
    625             glDisable(GL_TEXTURE_2D);
    626             glClear(GL_COLOR_BUFFER_BIT);
    627 
    628             glColor3f(1, 1, 1);
    629             glRasterPos2f(0, 15);
    630             glutBitmapCharacter(GLUT_BITMAP_9_BY_15, i + 32);
    631 
    632             glEnable(GL_TEXTURE_2D);
    633             glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
    634             glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
    635                              0, kk->gl.height - 16, 16, 16, 0);
    636 
    637             glutMainLoopEvent();
    638             glutPostRedisplay();
     197            attrset(kk->ncurses.attr[*attr++]);
     198            addch(*chars++ & 0x7f);
    639199        }
    640200    }
    641     else
    642 #endif
    643     {
    644         /* Dummy */
    645     }
    646 
    647     kk->delay = 0;
    648     kk->rendertime = 0;
    649 
    650     return 0;
    651 }
    652 
    653 int _caca_end_graphics(caca_t *kk)
    654 {
    655 #if defined(USE_SLANG)
    656     /* Nothing to do */
    657 #endif
    658 #if defined(USE_NCURSES)
    659     /* Nothing to do */
    660 #endif
    661 #if defined(USE_CONIO)
    662     if(kk->driver == CACA_DRIVER_CONIO)
    663     {
    664         free(kk->conio.screen);
    665     }
    666     else
    667 #endif
    668 #if defined(USE_X11)
    669     if(kk->driver == CACA_DRIVER_X11)
    670     {
    671         XSync(kk->x11.dpy, False);
    672 #if defined(HAVE_X11_XKBLIB_H)
    673         if(!kk->x11.autorepeat)
    674             XAutoRepeatOn(kk->x11.dpy);
    675 #endif
    676         XFreePixmap(kk->x11.dpy, kk->x11.pixmap);
    677         XFreeFont(kk->x11.dpy, kk->x11.font_struct);
    678         XFreeGC(kk->x11.dpy, kk->x11.gc);
    679         XUnmapWindow(kk->x11.dpy, kk->x11.window);
    680         XDestroyWindow(kk->x11.dpy, kk->x11.window);
    681         XCloseDisplay(kk->x11.dpy);
    682     }
    683     else
    684 #endif
    685 #if defined(USE_WIN32)
    686     if(kk->driver == CACA_DRIVER_WIN32)
    687     {
    688         SetConsoleActiveScreenBuffer(kk->win32.hout);
    689         CloseHandle(kk->win32.back);
    690         CloseHandle(kk->win32.front);
    691     }
    692     else
    693 #endif
    694 #if defined(USE_GL)
    695     if(kk->driver == CACA_DRIVER_GL)
    696     {
    697         glutDestroyWindow(kk->gl.window);
    698     }
    699     else
    700 #endif
    701     {
    702         /* Dummy */
    703     }
    704 
    705     return 0;
    706 }
    707 #endif /* _DOXYGEN_SKIP_ME */
    708 
    709 /** \brief Set the window title.
    710  *
    711  *  If libcaca runs in a window, try to change its title. This works with
    712  *  the X11 and Win32 drivers.
    713  *
    714  *  \param title The desired window title.
    715  *  \return 0 upon success, a non-zero value if an error occurs.
    716  */
    717 int caca_set_window_title(caca_t *kk, char const *title)
    718 {
    719 #if defined(USE_X11)
    720     if(kk->driver == CACA_DRIVER_X11)
    721     {
    722         XStoreName(kk->x11.dpy, kk->x11.window, title);
    723     }
    724     else
    725 #endif
    726 #if defined(USE_WIN32)
    727     if(kk->driver == CACA_DRIVER_WIN32)
    728     {
    729         SetConsoleTitle(title);
    730     }
    731     else
    732 #endif
    733 #if defined(USE_GL)
    734     if(kk->driver == CACA_DRIVER_GL)
    735     {
    736         glutSetWindowTitle(title);
    737     }
    738     else
    739 #endif
    740     {
    741         /* Not supported */
    742         return -1;
    743     }
    744 
    745     return 0;
    746 }
    747 
    748 /** \brief Get the window width.
    749  *
    750  *  If libcaca runs in a window, get the usable window width. This value can
    751  *  be used for aspect ratio calculation. If libcaca does not run in a window
    752  *  or if there is no way to know the font size, assume a 6x10 font is being
    753  *  used. Note that the units are not necessarily pixels.
    754  *
    755  *  \return The window width.
    756  */
    757 unsigned int caca_get_window_width(caca_t *kk)
    758 {
    759 #if defined(USE_X11)
    760     if(kk->driver == CACA_DRIVER_X11)
    761     {
    762         return kk->qq->width * kk->x11.font_width;
    763     }
    764     else
    765 #endif
    766 #if defined(USE_WIN32)
    767     if(kk->driver == CACA_DRIVER_WIN32)
    768     {
    769         /* FIXME */
    770     }
    771     else
    772 #endif
    773 #if defined(USE_GL)
    774     if(kk->driver == CACA_DRIVER_GL)
    775     {
    776         return kk->gl.width;
    777     }
    778     else
    779 #endif
    780     {
    781         /* Dummy */
    782     }
    783 
    784     /* Fallback to a 6x10 font */
    785     return kk->qq->width * 6;
    786 }
    787 
    788 /** \brief Get the window height.
    789  *
    790  *  If libcaca runs in a window, get the usable window height. This value can
    791  *  be used for aspect ratio calculation. If libcaca does not run in a window
    792  *  or if there is no way to know the font size, assume a 6x10 font is being
    793  *  used. Note that the units are not necessarily pixels.
    794  *
    795  *  \return The window height.
    796  */
    797 unsigned int caca_get_window_height(caca_t *kk)
    798 {
    799 #if defined(USE_X11)
    800     if(kk->driver == CACA_DRIVER_X11)
    801     {
    802         return kk->qq->height * kk->x11.font_height;
    803     }
    804     else
    805 #endif
    806 #if defined(USE_WIN32)
    807     if(kk->driver == CACA_DRIVER_WIN32)
    808     {
    809         /* FIXME */
    810     }
    811     else
    812 #endif
    813 #if defined(USE_GL)
    814     if(kk->driver == CACA_DRIVER_GL)
    815     {
    816         return kk->gl.height;
    817     }
    818     else
    819 #endif
    820     {
    821         /* Dummy */
    822     }
    823 
    824     /* Fallback to a 6x10 font */
    825     return kk->qq->height * 10;
    826 }
    827 
    828 /** \brief Set the refresh delay.
    829  *
    830  *  This function sets the refresh delay in microseconds. The refresh delay
    831  *  is used by caca_display() to achieve constant framerate. See the
    832  *  caca_display() documentation for more details.
    833  *
    834  *  If the argument is zero, constant framerate is disabled. This is the
    835  *  default behaviour.
    836  *
    837  *  \param usec The refresh delay in microseconds.
    838  */
    839 void caca_set_delay(caca_t *kk, unsigned int usec)
    840 {
    841     kk->delay = usec;
    842 }
    843 
    844 /** \brief Get the average rendering time.
    845  *
    846  *  This function returns the average rendering time, which is the average
    847  *  measured time between two caca_display() calls, in microseconds. If
    848  *  constant framerate was activated by calling caca_set_delay(), the average
    849  *  rendering time will not be considerably shorter than the requested delay
    850  *  even if the real rendering time was shorter.
    851  *
    852  *  \return The render time in microseconds.
    853  */
    854 unsigned int caca_get_rendertime(caca_t *kk)
    855 {
    856     return kk->rendertime;
    857 }
    858 
    859 /** \brief Flush pending changes and redraw the screen.
    860  *
    861  *  This function flushes all graphical operations and prints them to the
    862  *  screen. Nothing will show on the screen until caca_display() is
    863  *  called.
    864  *
    865  *  If caca_set_delay() was called with a non-zero value, caca_display()
    866  *  will use that value to achieve constant framerate: if two consecutive
    867  *  calls to caca_display() are within a time range shorter than the value
    868  *  set with caca_set_delay(), the second call will wait a bit before
    869  *  performing the screen refresh.
    870  */
    871 void caca_display(caca_t *kk)
    872 {
    873 #if !defined(_DOXYGEN_SKIP_ME)
    874 #define IDLE_USEC 10000
    875 #endif
    876     int ticks = kk->lastticks + _caca_getticks(&kk->timer);
    877 
    878 #if defined(USE_SLANG)
    879     if(kk->driver == CACA_DRIVER_SLANG)
    880     {
    881         int x, y;
    882         uint8_t *attr = kk->qq->attr;
    883         uint32_t *chars = kk->qq->chars;
    884         for(y = 0; y < (int)kk->qq->height; y++)
    885         {
    886             SLsmg_gotorc(y, 0);
    887             for(x = kk->qq->width; x--; )
    888             {
    889 #if defined(OPTIMISE_SLANG_PALETTE)
    890                 /* If foreground == background, just don't use this colour
    891                  * pair, and print a space instead of the real character. */
    892                 uint8_t fgcolor = *attr & 0xf;
    893                 uint8_t bgcolor = *attr >> 4;
    894                 if(fgcolor != bgcolor)
    895                 {
    896                     SLsmg_set_color(slang_assoc[*attr++]);
    897                     SLsmg_write_char(*chars++ & 0x7f);
    898                 }
    899                 else
    900                 {
    901                     if(fgcolor == CUCUL_COLOR_BLACK)
    902                         fgcolor = CUCUL_COLOR_WHITE;
    903                     else if(fgcolor == CUCUL_COLOR_WHITE
    904                              || fgcolor <= CUCUL_COLOR_LIGHTGRAY)
    905                         fgcolor = CUCUL_COLOR_BLACK;
    906                     else
    907                         fgcolor = CUCUL_COLOR_WHITE;
    908                     SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]);
    909                     SLsmg_write_char(' ');
    910                     chars++;
    911                     attr++;
    912                 }
    913 #else
    914                 SLsmg_set_color(*attr++);
    915                 SLsmg_write_char(*chars++ & 0x7f);
    916 #endif
    917             }
    918         }
    919         SLsmg_refresh();
    920     }
    921     else
    922 #endif
    923 #if defined(USE_NCURSES)
    924     if(kk->driver == CACA_DRIVER_NCURSES)
    925     {
    926         int x, y;
    927         uint8_t *attr = kk->qq->attr;
    928         uint32_t *chars = kk->qq->chars;
    929         for(y = 0; y < (int)kk->qq->height; y++)
    930         {
    931             move(y, 0);
    932             for(x = kk->qq->width; x--; )
    933             {
    934                 attrset(kk->ncurses.attr[*attr++]);
    935                 addch(*chars++ & 0x7f);
    936             }
    937         }
    938         refresh();
    939     }
    940     else
    941 #endif
    942 #if defined(USE_CONIO)
    943     if(kk->driver == CACA_DRIVER_CONIO)
    944     {
    945         int n;
    946         char *screen = kk->conio.screen;
    947         uint8_t *attr = kk->qq->attr;
    948         uint32_t *chars = kk->qq->chars;
    949         for(n = kk->qq->height * kk->qq->width; n--; )
    950         {
    951             *screen++ = *chars++ & 0x7f;
    952             *screen++ = *attr++;
    953         }
    954 #   if defined(SCREENUPDATE_IN_PC_H)
    955         ScreenUpdate(kk->conio.screen);
    956 #   else
    957         /* FIXME */
    958 #   endif
    959     }
    960     else
    961 #endif
    962 #if defined(USE_X11)
    963     if(kk->driver == CACA_DRIVER_X11)
    964     {
    965         unsigned int x, y, len;
    966 
    967         /* First draw the background colours. Splitting the process in two
    968          * loops like this is actually slightly faster. */
    969         for(y = 0; y < kk->qq->height; y++)
    970         {
    971             for(x = 0; x < kk->qq->width; x += len)
    972             {
    973                 uint8_t *attr = kk->qq->attr + x + y * kk->qq->width;
    974 
    975                 len = 1;
    976                 while(x + len < kk->qq->width
    977                        && (attr[len] >> 4) == (attr[0] >> 4))
    978                     len++;
    979 
    980                 XSetForeground(kk->x11.dpy, kk->x11.gc,
    981                                kk->x11.colors[attr[0] >> 4]);
    982                 XFillRectangle(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc,
    983                                x * kk->x11.font_width, y * kk->x11.font_height,
    984                                len * kk->x11.font_width, kk->x11.font_height);
    985             }
    986         }
    987 
    988         /* Then print the foreground characters */
    989         for(y = 0; y < kk->qq->height; y++)
    990         {
    991             for(x = 0; x < kk->qq->width; x += len)
    992             {
    993                 char buffer[BUFSIZ]; /* FIXME: use a smaller buffer */
    994                 uint32_t *chars = kk->qq->chars + x + y * kk->qq->width;
    995                 uint8_t *attr = kk->qq->attr + x + y * kk->qq->width;
    996 
    997                 len = 1;
    998 
    999                 /* Skip spaces */
    1000                 if(chars[0] == ' ')
    1001                     continue;
    1002 
    1003                 buffer[0] = chars[0] & 0x7f;
    1004 
    1005                 while(x + len < kk->qq->width
    1006                        && (attr[len] & 0xf) == (attr[0] & 0xf))
    1007                 {
    1008                     buffer[len] = chars[len] & 0x7f;
    1009                     len++;
    1010                 }
    1011 
    1012                 XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[attr[0] & 0xf]);
    1013                 XDrawString(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc,
    1014                             x * kk->x11.font_width,
    1015                             (y + 1) * kk->x11.font_height - kk->x11.font_offset,
    1016                             buffer, len);
    1017             }
    1018         }
    1019 
    1020         XCopyArea(kk->x11.dpy, kk->x11.pixmap, kk->x11.window, kk->x11.gc, 0, 0,
    1021                   kk->qq->width * kk->x11.font_width, kk->qq->height * kk->x11.font_height,
    1022                   0, 0);
    1023         XFlush(kk->x11.dpy);
    1024     }
    1025     else
    1026 #endif
    1027 #if defined(USE_WIN32)
    1028     if(kk->driver == CACA_DRIVER_WIN32)
    1029     {
    1030         COORD size, pos;
    1031         SMALL_RECT rect;
    1032         unsigned int i;
    1033 
    1034         /* Render everything to our back buffer */
    1035         for(i = 0; i < kk->qq->width * kk->qq->height; i++)
    1036         {
    1037             kk->win32.buffer[i].Char.AsciiChar = kk->qq->chars[i] & 0x7f;
    1038             kk->win32.buffer[i].Attributes =
    1039                     win32_fg_palette[kk->qq->attr[i] & 0xf]
    1040                      | win32_bg_palette[kk->qq->attr[i] >> 4];
    1041         }
    1042 
    1043         /* Blit the back buffer to the front buffer */
    1044         size.X = kk->qq->width;
    1045         size.Y = kk->qq->height;
    1046         pos.X = pos.Y = 0;
    1047         rect.Left = rect.Top = 0;
    1048         rect.Right = kk->qq->width - 1;
    1049         rect.Bottom = kk->qq->height - 1;
    1050         WriteConsoleOutput(kk->win32.front, kk->win32.buffer, size, pos, &rect);
    1051     }
    1052     else
    1053 #endif
    1054 #if defined(USE_GL)
    1055     if(kk->driver == CACA_DRIVER_GL)
    1056     {
    1057         unsigned int x, y, line;
    1058 
    1059         glClear(GL_COLOR_BUFFER_BIT);
    1060 
    1061         line = 0;
    1062         for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
    1063         {
    1064             uint8_t *attr = kk->qq->attr + line * kk->qq->width;
    1065 
    1066             for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
    1067             {
    1068                 glDisable(GL_TEXTURE_2D);
    1069                 glColor4bv(gl_bgpal[attr[0] >> 4]);
    1070                 glBegin(GL_QUADS);
    1071                     glVertex2f(x, y);
    1072                     glVertex2f(x + kk->gl.font_width, y);
    1073                     glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height);
    1074                     glVertex2f(x, y + kk->gl.font_height);
    1075                 glEnd();
    1076 
    1077                 attr++;
    1078             }
    1079 
    1080             line++;
    1081         }
    1082 
    1083         /* 2nd pass, avoids changing render state too much */
    1084         glEnable(GL_BLEND);
    1085         glEnable(GL_TEXTURE_2D);
    1086         glBlendFunc(GL_ONE, GL_ONE);
    1087 
    1088         line = 0;
    1089         for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
    1090         {
    1091             uint8_t *attr = kk->qq->attr + line * kk->qq->width;
    1092             uint32_t *chars = kk->qq->chars + line * kk->qq->width;
    1093 
    1094             for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
    1095             {
    1096                 if(*chars != (uint32_t)' ')
    1097                 {
    1098                     char ch = *chars & 0x7f;
    1099 
    1100                     /* FIXME: check ch bounds */
    1101                     glBindTexture(GL_TEXTURE_2D, kk->gl.id[ch - 32]);
    1102                     glColor4bv(gl_bgpal[attr[0] & 0xf]);
    1103                     glBegin(GL_QUADS);
    1104                         glTexCoord2f(0, kk->gl.sh);
    1105                         glVertex2f(x, y);
    1106                         glTexCoord2f(kk->gl.sw, kk->gl.sh);
    1107                         glVertex2f(x + kk->gl.font_width, y);
    1108                         glTexCoord2f(kk->gl.sw, 0);
    1109                         glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height);
    1110                         glTexCoord2f(0, 0);
    1111                         glVertex2f(x, y + kk->gl.font_height);
    1112                     glEnd();
    1113                 }
    1114 
    1115                 attr++;
    1116                 chars++;
    1117             }
    1118             line++;
    1119         }
    1120         glDisable(GL_BLEND);
    1121         glDisable(GL_TEXTURE_2D);
    1122 
    1123         glutMainLoopEvent();
    1124         glutSwapBuffers();
    1125         glutPostRedisplay();
    1126     }
    1127     else
    1128 #endif
    1129     {
    1130         /* Dummy */
    1131     }
    1132 
    1133     /* FIXME handle this somewhere else */
    1134     if(kk->resize)
    1135     {
    1136         kk->resize = 0;
    1137         caca_handle_resize(kk);
    1138     }
    1139 
    1140     /* Wait until kk->delay + time of last call */
    1141     ticks += _caca_getticks(&kk->timer);
    1142     for(ticks += _caca_getticks(&kk->timer);
    1143         ticks + IDLE_USEC < (int)kk->delay;
    1144         ticks += _caca_getticks(&kk->timer))
    1145     {
    1146         _caca_sleep(IDLE_USEC);
    1147     }
    1148 
    1149     /* Update the sliding mean of the render time */
    1150     kk->rendertime = (7 * kk->rendertime + ticks) / 8;
    1151 
    1152     kk->lastticks = ticks - kk->delay;
    1153 
    1154     /* If we drifted too much, it's bad, bad, bad. */
    1155     if(kk->lastticks > (int)kk->delay)
    1156         kk->lastticks = 0;
    1157 }
    1158 
    1159 /*
    1160  * XXX: following functions are local
    1161  */
    1162 
    1163 static void caca_handle_resize(caca_t *kk)
     201    refresh();
     202}
     203
     204void ncurses_handle_resize(caca_t *kk)
    1164205{
    1165206    unsigned int new_width, new_height;
     207    struct winsize size;
    1166208
    1167209    new_width = kk->qq->width;
    1168210    new_height = kk->qq->height;
    1169211
    1170 #if defined(USE_SLANG)
    1171     if(kk->driver == CACA_DRIVER_SLANG)
     212    if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0)
    1172213    {
    1173         SLtt_get_screen_size();
    1174         new_width = SLtt_Screen_Cols;
    1175         new_height = SLtt_Screen_Rows;
    1176 
    1177         if(new_width != kk->qq->width || new_height != kk->qq->height)
    1178             SLsmg_reinit_smg();
     214        new_width = size.ws_col;
     215        new_height = size.ws_row;
     216#if defined(HAVE_RESIZE_TERM)
     217        resize_term(new_height, new_width);
     218#else
     219        resizeterm(new_height, new_width);
     220#endif
     221        wrefresh(curscr);
    1179222    }
    1180     else
    1181 #endif
    1182 #if defined(USE_NCURSES)
    1183     if(kk->driver == CACA_DRIVER_NCURSES)
    1184     {
    1185         struct winsize size;
    1186 
    1187         if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0)
    1188         {
    1189             new_width = size.ws_col;
    1190             new_height = size.ws_row;
    1191 #if defined(HAVE_RESIZE_TERM)
    1192             resize_term(new_height, new_width);
    1193 #else
    1194             resizeterm(new_height, new_width);
    1195 #endif
    1196             wrefresh(curscr);
    1197         }
    1198     }
    1199     else
    1200 #endif
    1201 #if defined(USE_CONIO)
    1202     if(kk->driver == CACA_DRIVER_CONIO)
    1203     {
    1204         /* Nothing to do here. */
    1205     }
    1206     else
    1207 #endif
    1208 #if defined(USE_X11)
    1209     if(kk->driver == CACA_DRIVER_X11)
    1210     {
    1211         Pixmap new_pixmap;
    1212 
    1213         new_width = kk->x11.new_width;
    1214         new_height = kk->x11.new_height;
    1215 
    1216         new_pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window,
    1217                                    kk->qq->width * kk->x11.font_width,
    1218                                    kk->qq->height * kk->x11.font_height,
    1219                                    DefaultDepth(kk->x11.dpy,
    1220                                                 DefaultScreen(kk->x11.dpy)));
    1221         XCopyArea(kk->x11.dpy, kk->x11.pixmap, new_pixmap, kk->x11.gc, 0, 0,
    1222                   kk->qq->width * kk->x11.font_width,
    1223                   kk->qq->height * kk->x11.font_height, 0, 0);
    1224         XFreePixmap(kk->x11.dpy, kk->x11.pixmap);
    1225         kk->x11.pixmap = new_pixmap;
    1226     }
    1227     else
    1228 #endif
    1229 #if defined(USE_WIN32)
    1230     if(kk->driver == CACA_DRIVER_WIN32)
    1231     {
    1232         /* Nothing to do here. */
    1233     }
    1234     else
    1235 #endif
    1236 #if defined(USE_GL)
    1237     if(kk->driver == CACA_DRIVER_GL)
    1238     {
    1239         kk->gl.width = kk->gl.new_width;
    1240         kk->gl.height = kk->gl.new_height;
    1241 
    1242         new_width = kk->gl.width / kk->gl.font_width;
    1243         new_height = (kk->gl.height / kk->gl.font_height) + 1;
    1244 
    1245         glMatrixMode(GL_PROJECTION);
    1246         glPushMatrix();
    1247         glLoadIdentity();
    1248 
    1249         glViewport(0, 0, kk->gl.width, kk->gl.height);
    1250         gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
    1251         glMatrixMode(GL_MODELVIEW);
    1252     }
    1253     else
    1254 #endif
    1255     {
    1256         /* Dummy */
    1257     }
    1258 
    1259     /* Tell libcucul we changed size */
    1260     if(new_width != kk->qq->width || new_height != kk->qq->height)
    1261         cucul_set_size(kk->qq, new_width, new_height);
    1262 }
    1263 
    1264 #if defined(USE_SLANG)
    1265 static void slang_init_palette(void)
    1266 {
    1267     /* See SLang ref., 5.4.4. */
    1268     static char *slang_colors[16] =
    1269     {
    1270         /* Standard colours */
    1271         "black",
    1272         "blue",
    1273         "green",
    1274         "cyan",
    1275         "red",
    1276         "magenta",
    1277         "brown",
    1278         "lightgray",
    1279         /* Bright colours */
    1280         "gray",
    1281         "brightblue",
    1282         "brightgreen",
    1283         "brightcyan",
    1284         "brightred",
    1285         "brightmagenta",
    1286         "yellow",
    1287         "white",
    1288     };
    1289 
    1290 #if defined(OPTIMISE_SLANG_PALETTE)
    1291     int i;
    1292 
    1293     for(i = 0; i < 16 * 16; i++)
    1294         SLtt_set_color(i, NULL, slang_colors[slang_palette[i * 2]],
    1295                                 slang_colors[slang_palette[i * 2 + 1]]);
    1296 #else
    1297     int fg, bg;
    1298 
    1299     for(bg = 0; bg < 16; bg++)
    1300         for(fg = 0; fg < 16; fg++)
    1301         {
    1302             int i = fg + 16 * bg;
    1303             SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]);
    1304         }
    1305 #endif
    1306 }
    1307 #endif /* USE_SLANG */
    1308 
    1309 #if defined(USE_X11)
    1310 static int x11_error_handler(Display *dpy, XErrorEvent *event)
    1311 {
    1312     /* Ignore the error */
    1313     return 0;
    1314 }
    1315 #endif
    1316 
    1317 #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
     223}
     224
     225/*
     226 * XXX: following functions are local
     227 */
     228
     229#if defined(HAVE_SIGNAL)
    1318230static RETSIGTYPE sigwinch_handler(int sig)
    1319231{
     
    1324236#endif
    1325237
    1326 #if defined(USE_GL)
    1327 static void gl_handle_keyboard(unsigned char key, int x, int y)
    1328 {
    1329     caca_t *kk = gl_kk;
    1330 
    1331     kk->gl.key = key;
    1332 }
    1333 
    1334 static void gl_handle_special_key(int key, int x, int y)
    1335 {
    1336     caca_t *kk = gl_kk;
    1337 
    1338     kk->gl.special_key = key;
    1339 }
    1340 
    1341 static void gl_handle_reshape(int w, int h)
    1342 {
    1343     caca_t *kk = gl_kk;
    1344 
    1345     if(kk->gl.bit) /* Do not handle reshaping at the first time */
    1346     {
    1347         kk->gl.new_width = w;
    1348         kk->gl.new_height = h;
    1349 
    1350         kk->gl.resized = 1;
    1351     }
    1352     else
    1353         kk->gl.bit = 1;
    1354 }
    1355 
    1356 static void gl_handle_mouse(int button, int state, int x, int y)
    1357 {
    1358     caca_t *kk = gl_kk;
    1359 
    1360     kk->gl.mouse_clicked = 1;
    1361     kk->gl.mouse_button = button;
    1362     kk->gl.mouse_state = state;
    1363     kk->gl.mouse_x = x / kk->gl.font_width;
    1364     kk->gl.mouse_y = y / kk->gl.font_height;
    1365     kk->gl.mouse_changed = 1;
    1366 }
    1367 
    1368 static void gl_handle_mouse_motion(int x, int y)
    1369 {
    1370     caca_t *kk = gl_kk;
    1371 
    1372     kk->gl.mouse_x = x / kk->gl.font_width;
    1373     kk->gl.mouse_y = y / kk->gl.font_height;
    1374     kk->gl.mouse_changed = 1;
    1375 }
    1376 #endif
    1377 
     238/*
     239 * Driver initialisation
     240 */
     241
     242void ncurses_init_driver(caca_t *kk)
     243{
     244    kk->driver.driver = CACA_DRIVER_NCURSES;
     245
     246    kk->driver.init_graphics = ncurses_init_graphics;
     247    kk->driver.end_graphics = ncurses_end_graphics;
     248    kk->driver.set_window_title = ncurses_set_window_title;
     249    kk->driver.get_window_width = ncurses_get_window_width;
     250    kk->driver.get_window_height = ncurses_get_window_height;
     251    kk->driver.display = ncurses_display;
     252    kk->driver.handle_resize = ncurses_handle_resize;
     253}
     254
     255#endif /* USE_NCURSES */
     256
  • libcaca/trunk/caca/driver_slang.c

    r537 r539  
    2020#include "config.h"
    2121
    22 #if defined(USE_SLANG)
    23 #   if defined(HAVE_SLANG_SLANG_H)
    24 #       include <slang/slang.h>
    25 #   else
    26 #       include <slang.h>
    27 #   endif
    28 #endif
    29 #if defined(USE_NCURSES)
    30 #   if defined(HAVE_NCURSES_H)
    31 #       include <ncurses.h>
    32 #   else
    33 #       include <curses.h>
    34 #   endif
    35 #endif
    36 #if defined(USE_CONIO)
    37 #   include <conio.h>
    38 #   if defined(SCREENUPDATE_IN_PC_H)
    39 #       include <pc.h>
    40 #   endif
    41 #endif
    42 #if defined(USE_X11)
    43 #   include <X11/Xlib.h>
    44 #   if defined(HAVE_X11_XKBLIB_H)
    45 #       include <X11/XKBlib.h>
    46 #   endif
    47 #endif
    48 #if defined(USE_WIN32)
    49 #   include <windows.h>
    50 #endif
    51 #if defined(USE_GL)
    52 #   include <GL/gl.h>
    53 #   include <GL/glut.h>
    54 #   include <GL/freeglut_ext.h>
    55 #endif
    5622#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME)
    5723#   include <inttypes.h>
     
    6127#endif
    6228
     29#if defined(USE_SLANG)
     30
     31#if defined(HAVE_SLANG_SLANG_H)
     32#   include <slang/slang.h>
     33#else
     34#   include <slang.h>
     35#endif
     36
    6337#include <stdio.h> /* BUFSIZ */
    6438#include <string.h>
     
    7246#   include <signal.h>
    7347#endif
    74 #if defined(HAVE_SYS_IOCTL_H)
    75 #   include <sys/ioctl.h>
    76 #endif
    7748
    7849#include "caca.h"
     
    8556 */
    8657
    87 #if defined(USE_SLANG)
    8858/* Tables generated by test/optipal.c */
    8959static int const slang_palette[2*16*16] =
     
    142112    123, 149, 158, 167, 176, 185, 194, 19, 125, 21, 30, 39, 48, 57, 66, 255,
    143113};
    144 #endif
    145 
    146 #if defined(USE_WIN32)
    147 static int const win32_fg_palette[] =
    148 {
    149     0,
    150     FOREGROUND_BLUE,
    151     FOREGROUND_GREEN,
    152     FOREGROUND_GREEN | FOREGROUND_BLUE,
    153     FOREGROUND_RED,
    154     FOREGROUND_RED | FOREGROUND_BLUE,
    155     FOREGROUND_RED | FOREGROUND_GREEN,
    156     FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
    157     FOREGROUND_INTENSITY,
    158     FOREGROUND_INTENSITY | FOREGROUND_BLUE,
    159     FOREGROUND_INTENSITY | FOREGROUND_GREEN,
    160     FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE,
    161     FOREGROUND_INTENSITY | FOREGROUND_RED,
    162     FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE,
    163     FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN,
    164     FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
    165 };
    166 
    167 static int const win32_bg_palette[] =
    168 {
    169     0,
    170     BACKGROUND_BLUE,
    171     BACKGROUND_GREEN,
    172     BACKGROUND_GREEN | BACKGROUND_BLUE,
    173     BACKGROUND_RED,
    174     BACKGROUND_RED | BACKGROUND_BLUE,
    175     BACKGROUND_RED | BACKGROUND_GREEN,
    176     BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
    177     BACKGROUND_INTENSITY,
    178     BACKGROUND_INTENSITY | BACKGROUND_BLUE,
    179     BACKGROUND_INTENSITY | BACKGROUND_GREEN,
    180     BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE,
    181     BACKGROUND_INTENSITY | BACKGROUND_RED,
    182     BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE,
    183     BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN,
    184     BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
    185 };
    186 #endif
    187 
    188 #if defined(USE_GL)
    189 /* Ok, I just suck. */
    190 static GLbyte const gl_bgpal[][4] =
    191 {
    192     { 0x00, 0x00, 0x00, 0x7f },
    193     { 0x00, 0x00, 0x3f, 0x7f },
    194     { 0x00, 0x3f, 0x00, 0x7f },
    195     { 0x00, 0x3f, 0x3f, 0x7f },
    196     { 0x3f, 0x00, 0x00, 0x7f },
    197     { 0x3f, 0x00, 0x3f, 0x7f },
    198     { 0x3f, 0x3f, 0x00, 0x7f },
    199     { 0x3f, 0x3f, 0x3f, 0x7f },
    200     // + intensity
    201     { 0x00, 0x00, 0x00, 0x7f },
    202     { 0x00, 0x00, 0x7f, 0x7f },
    203     { 0x00, 0x7f, 0x00, 0x7f },
    204     { 0x00, 0x7f, 0x7f, 0x7f },
    205     { 0x7f, 0x00, 0x00, 0x7f },
    206     { 0x7f, 0x00, 0x7f, 0x7f },
    207     { 0x7f, 0x7f, 0x00, 0x7f },
    208     { 0x7f, 0x7f, 0x7f, 0x7f }
    209 };
    210 
    211 static caca_t *gl_kk; /* FIXME: we ought to get rid of this */
    212 #endif
     114
     115int slang_init_graphics(caca_t *);
     116int slang_end_graphics(caca_t *);
     117int slang_set_window_title(caca_t *, char const *);
     118unsigned int slang_get_window_width(caca_t *);
     119unsigned int slang_get_window_height(caca_t *);
     120void slang_display(caca_t *);
     121void slang_handle_resize(caca_t *);
    213122
    214123/*
    215124 * Local functions
    216125 */
    217 static void caca_handle_resize(caca_t *kk);
    218 
    219 #if defined(USE_SLANG)
    220126static void slang_init_palette(void);
    221 #endif
    222 
    223 #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
     127
     128#if defined(HAVE_SIGNAL)
    224129static RETSIGTYPE sigwinch_handler(int);
    225130static caca_t *sigwinch_kk; /* FIXME: we ought to get rid of this */
    226131#endif
    227132
    228 #if defined(USE_X11)
    229 static int x11_error_handler(Display *, XErrorEvent *);
    230 #endif
    231 
    232 #if defined(USE_GL)
    233 static void gl_handle_keyboard(unsigned char, int, int);
    234 static void gl_handle_special_key(int, int, int);
    235 static void gl_handle_reshape(int, int);
    236 static void gl_handle_mouse(int, int, int, int);
    237 static void gl_handle_mouse_motion(int, int);
    238 #endif
    239 
    240133#if !defined(_DOXYGEN_SKIP_ME)
    241 int _caca_init_graphics(caca_t *kk)
    242 {
    243 #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
     134int slang_init_graphics(caca_t *kk)
     135{
     136#if defined(HAVE_SIGNAL)
    244137    sigwinch_kk = kk;
    245138    signal(SIGWINCH, sigwinch_handler);
    246139#endif
    247140
    248 #if defined(USE_SLANG)
    249     if(kk->driver == CACA_DRIVER_SLANG)
     141    /* Initialise slang library */
     142    SLsig_block_signals();
     143    SLtt_get_terminfo();
     144
     145    if(SLkp_init() == -1)
    250146    {
    251         slang_init_palette();
    252 
    253         /* Disable alt charset support so that we get a chance to have all
    254          * 256 colour pairs */
    255         SLtt_Has_Alt_Charset = 0;
    256 
    257         cucul_set_size(kk->qq, SLtt_Screen_Cols, SLtt_Screen_Rows);
     147        SLsig_unblock_signals();
     148        return NULL;
    258149    }
    259     else
    260 #endif
    261 #if defined(USE_NCURSES)
    262     if(kk->driver == CACA_DRIVER_NCURSES)
     150
     151    SLang_init_tty(-1, 0, 1);
     152
     153    if(SLsmg_init_smg() == -1)
    263154    {
    264         static int curses_colors[] =
     155        SLsig_unblock_signals();
     156        return NULL;
     157    }
     158
     159    SLsig_unblock_signals();
     160
     161    SLsmg_cls();
     162    SLtt_set_cursor_visibility(0);
     163    SLkp_define_keysym("\e[M", 1001);
     164    SLtt_set_mouse_mode(1, 0);
     165    SLsmg_refresh();
     166
     167    /* Disable scrolling so that hashmap scrolling optimization code
     168     * does not cause ugly refreshes due to slow terminals */
     169    SLtt_Term_Cannot_Scroll = 1;
     170
     171    slang_init_palette();
     172
     173    /* Disable alt charset support so that we get a chance to have all
     174     * 256 colour pairs */
     175    SLtt_Has_Alt_Charset = 0;
     176
     177    cucul_set_size(kk->qq, SLtt_Screen_Cols, SLtt_Screen_Rows);
     178
     179    return 0;
     180}
     181
     182int slang_end_graphics(caca_t *kk)
     183{
     184    SLtt_set_mouse_mode(0, 0);
     185    SLtt_set_cursor_visibility(1);
     186    SLang_reset_tty();
     187    SLsmg_reset_smg();
     188
     189    return 0;
     190}
     191#endif /* _DOXYGEN_SKIP_ME */
     192
     193int slang_set_window_title(caca_t *kk, char const *title)
     194{
     195    return 0;
     196}
     197
     198unsigned int slang_get_window_width(caca_t *kk)
     199{
     200    /* Fallback to a 6x10 font */
     201    return kk->qq->width * 6;
     202}
     203
     204unsigned int slang_get_window_height(caca_t *kk)
     205{
     206    /* Fallback to a 6x10 font */
     207    return kk->qq->height * 10;
     208}
     209
     210void slang_display(caca_t *kk)
     211{
     212    int x, y;
     213    uint8_t *attr = kk->qq->attr;
     214    uint32_t *chars = kk->qq->chars;
     215    for(y = 0; y < (int)kk->qq->height; y++)
     216    {
     217        SLsmg_gotorc(y, 0);
     218        for(x = kk->qq->width; x--; )
    265219        {
    266             /* Standard curses colours */
    267             COLOR_BLACK,
    268             COLOR_BLUE,
    269             COLOR_GREEN,
    270             COLOR_CYAN,
    271             COLOR_RED,
    272             COLOR_MAGENTA,
    273             COLOR_YELLOW,
    274             COLOR_WHITE,
    275             /* Extra values for xterm-16color */
    276             COLOR_BLACK + 8,
    277             COLOR_BLUE + 8,
    278             COLOR_GREEN + 8,
    279             COLOR_CYAN + 8,
    280             COLOR_RED + 8,
    281             COLOR_MAGENTA + 8,
    282             COLOR_YELLOW + 8,
    283             COLOR_WHITE + 8
    284         };
    285 
    286         int fg, bg, max;
    287 
    288         /* Activate colour */
    289         start_color();
    290 
    291         /* If COLORS == 16, it means the terminal supports full bright colours
    292          * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
    293          * we can build 16*16 colour pairs.
    294          * If COLORS == 8, it means the terminal does not know about bright
    295          * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
    296          * and \e[5m). We can only build 8*8 colour pairs. */
    297         max = COLORS >= 16 ? 16 : 8;
    298 
    299         for(bg = 0; bg < max; bg++)
    300             for(fg = 0; fg < max; fg++)
     220#if defined(OPTIMISE_SLANG_PALETTE)
     221            /* If foreground == background, just don't use this colour
     222             * pair, and print a space instead of the real character. */
     223            uint8_t fgcolor = *attr & 0xf;
     224            uint8_t bgcolor = *attr >> 4;
     225            if(fgcolor != bgcolor)
    301226            {
    302                 /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
    303                  * is light gray on black. Some terminals don't like this
    304                  * colour pair to be redefined. */
    305                 int col = ((max + 7 - fg) % max) + max * bg;
    306                 init_pair(col, curses_colors[fg], curses_colors[bg]);
    307                 kk->ncurses.attr[fg + 16 * bg] = COLOR_PAIR(col);
    308 
    309                 if(max == 8)
    310                 {
    311                     /* Bright fg on simple bg */
    312                     kk->ncurses.attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
    313                     /* Simple fg on bright bg */
    314                     kk->ncurses.attr[fg + 16 * (bg + 8)] = A_BLINK
    315                                                         | COLOR_PAIR(col);
    316                     /* Bright fg on bright bg */
    317                     kk->ncurses.attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
    318                                                             | COLOR_PAIR(col);
    319                 }
     227                SLsmg_set_color(slang_assoc[*attr++]);
     228                SLsmg_write_char(*chars++ & 0x7f);
    320229            }
    321 
    322         cucul_set_size(kk->qq, COLS, LINES);
    323     }
    324     else
    325 #endif
    326 #if defined(USE_CONIO)
    327     if(kk->driver == CACA_DRIVER_CONIO)
    328     {
    329         gettextinfo(&kk->conio.ti);
    330         kk->conio.screen = malloc(2 * kk->conio.ti.screenwidth
    331                                 * kk->conio.ti.screenheight * sizeof(char));
    332         if(kk->conio.screen == NULL)
    333             return -1;
    334 #   if defined(SCREENUPDATE_IN_PC_H)
    335         ScreenRetrieve(kk->conio.screen);
    336 #   else
    337         /* FIXME */
    338 #   endif
    339         cucul_set_size(kk->qq, kk->conio.ti.screenwidth,
    340                                kk->conio.ti.screenheight);
    341     }
    342     else
    343 #endif
    344 #if defined(USE_X11)
    345     if(kk->driver == CACA_DRIVER_X11)
    346     {
    347         static int const x11_palette[] =
    348         {
    349             /* Standard curses colours */
    350             0x0,    0x0,    0x0,
    351             0x0,    0x0,    0x8000,
    352             0x0,    0x8000, 0x0,
    353             0x0,    0x8000, 0x8000,
    354             0x8000, 0x0,    0x0,
    355             0x8000, 0x0,    0x8000,
    356             0x8000, 0x8000, 0x0,
    357             0x8000, 0x8000, 0x8000,
    358             /* Extra values for xterm-16color */
    359             0x4000, 0x4000, 0x4000,
    360             0x4000, 0x4000, 0xffff,
    361             0x4000, 0xffff, 0x4000,
    362             0x4000, 0xffff, 0xffff,
    363             0xffff, 0x4000, 0x4000,
    364             0xffff, 0x4000, 0xffff,
    365             0xffff, 0xffff, 0x4000,
    366             0xffff, 0xffff, 0xffff,
    367         };
    368 
    369         Colormap colormap;
    370         XSetWindowAttributes x11_winattr;
    371         int (*old_error_handler)(Display *, XErrorEvent *);
    372         char const *fonts[] = { NULL, "8x13bold", "fixed" }, **parser;
    373         char const *geometry;
    374         unsigned int width = 0, height = 0;
    375         int i;
    376 
    377         geometry = getenv("CACA_GEOMETRY");
    378         if(geometry && *(geometry))
    379             sscanf(geometry, "%ux%u", &width, &height);
    380 
    381         if(width && height)
    382             cucul_set_size(kk->qq, width, height);
    383 
    384         kk->x11.dpy = XOpenDisplay(NULL);
    385         if(kk->x11.dpy == NULL)
    386             return -1;
    387 
    388         fonts[0] = getenv("CACA_FONT");
    389         if(fonts[0] && *fonts[0])
    390             parser = fonts;
    391         else
    392             parser = fonts + 1;
    393 
    394         /* Ignore font errors */
    395         old_error_handler = XSetErrorHandler(x11_error_handler);
    396 
    397         /* Parse our font list */
    398         for( ; ; parser++)
    399         {
    400             if(!*parser)
     230            else
    401231            {
    402                 XSetErrorHandler(old_error_handler);
    403                 XCloseDisplay(kk->x11.dpy);
    404                 return -1;
     232                if(fgcolor == CUCUL_COLOR_BLACK)
     233                    fgcolor = CUCUL_COLOR_WHITE;
     234                else if(fgcolor == CUCUL_COLOR_WHITE
     235                         || fgcolor <= CUCUL_COLOR_LIGHTGRAY)
     236                    fgcolor = CUCUL_COLOR_BLACK;
     237                else
     238                    fgcolor = CUCUL_COLOR_WHITE;
     239                SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]);
     240                SLsmg_write_char(' ');
     241                chars++;
     242                attr++;
    405243            }
    406 
    407             kk->x11.font = XLoadFont(kk->x11.dpy, *parser);
    408             if(!kk->x11.font)
    409                 continue;
    410 
    411             kk->x11.font_struct = XQueryFont(kk->x11.dpy, kk->x11.font);
    412             if(!kk->x11.font_struct)
    413             {
    414                 XUnloadFont(kk->x11.dpy, kk->x11.font);
    415                 continue;
    416             }
    417 
    418             break;
    419         }
    420 
    421         /* Reset the default X11 error handler */
    422         XSetErrorHandler(old_error_handler);
    423 
    424         kk->x11.font_width = kk->x11.font_struct->max_bounds.width;
    425         kk->x11.font_height = kk->x11.font_struct->max_bounds.ascent
    426                              + kk->x11.font_struct->max_bounds.descent;
    427         kk->x11.font_offset = kk->x11.font_struct->max_bounds.descent;
    428 
    429         colormap = DefaultColormap(kk->x11.dpy, DefaultScreen(kk->x11.dpy));
    430         for(i = 0; i < 16; i++)
    431         {
    432             XColor color;
    433             color.red = x11_palette[i * 3];
    434             color.green = x11_palette[i * 3 + 1];
    435             color.blue = x11_palette[i * 3 + 2];
    436             XAllocColor(kk->x11.dpy, colormap, &color);
    437             kk->x11.colors[i] = color.pixel;
    438         }
    439 
    440         x11_winattr.backing_store = Always;
    441         x11_winattr.background_pixel = kk->x11.colors[0];
    442         x11_winattr.event_mask = ExposureMask | StructureNotifyMask;
    443 
    444         kk->x11.window =
    445             XCreateWindow(kk->x11.dpy, DefaultRootWindow(kk->x11.dpy), 0, 0,
    446                           kk->qq->width * kk->x11.font_width,
    447                           kk->qq->height * kk->x11.font_height,
    448                           0, 0, InputOutput, 0,
    449                           CWBackingStore | CWBackPixel | CWEventMask,
    450                           &x11_winattr);
    451 
    452         XStoreName(kk->x11.dpy, kk->x11.window, "caca for X");
    453 
    454         XSelectInput(kk->x11.dpy, kk->x11.window, StructureNotifyMask);
    455         XMapWindow(kk->x11.dpy, kk->x11.window);
    456 
    457         kk->x11.gc = XCreateGC(kk->x11.dpy, kk->x11.window, 0, NULL);
    458         XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[15]);
    459         XSetFont(kk->x11.dpy, kk->x11.gc, kk->x11.font);
    460 
    461         for(;;)
    462         {
    463             XEvent event;
    464             XNextEvent(kk->x11.dpy, &event);
    465             if (event.type == MapNotify)
    466                 break;
    467         }
    468 
    469 #if defined(HAVE_X11_XKBLIB_H)
    470         /* Disable autorepeat */
    471         XkbSetDetectableAutoRepeat(kk->x11.dpy, True, &kk->x11.autorepeat);
    472         if(!kk->x11.autorepeat)
    473             XAutoRepeatOff(kk->x11.dpy);
    474 #endif
    475 
    476         XSelectInput(kk->x11.dpy, kk->x11.window, kk->x11.event_mask);
    477 
    478         XSync(kk->x11.dpy, False);
    479 
    480         kk->x11.pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window,
    481                                        kk->qq->width * kk->x11.font_width,
    482                                        kk->qq->height * kk->x11.font_height,
    483                                        DefaultDepth(kk->x11.dpy,
    484                                                 DefaultScreen(kk->x11.dpy)));
    485 
    486         kk->x11.new_width = kk->x11.new_height = 0;
    487     }
    488     else
    489 #endif
    490 #if defined(USE_WIN32)
    491     if(kk->driver == CACA_DRIVER_WIN32)
    492     {
    493         CONSOLE_CURSOR_INFO cci;
    494         CONSOLE_SCREEN_BUFFER_INFO csbi;
    495         COORD size;
    496 
    497         kk->win32.front =
    498             CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
    499                                       0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    500         if(!kk->win32.front || kk->win32.front == INVALID_HANDLE_VALUE)
    501             return -1;
    502 
    503         kk->win32.back =
    504             CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
    505                                       0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    506         if(!kk->win32.back || kk->win32.back == INVALID_HANDLE_VALUE)
    507             return -1;
    508 
    509         if(!GetConsoleScreenBufferInfo(kk->win32.hout, &csbi))
    510             return -1;
    511 
    512         /* Sample code to get the biggest possible window */
    513         //size = GetLargestConsoleWindowSize(kk->win32.hout);
    514         cucul_set_size(kk->qq, csbi.srWindow.Right - csbi.srWindow.Left + 1,
    515                                csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
    516         size.X = kk->qq->width;
    517         size.Y = kk->qq->height;
    518         SetConsoleScreenBufferSize(kk->win32.front, size);
    519         SetConsoleScreenBufferSize(kk->win32.back, size);
    520 
    521         SetConsoleMode(kk->win32.front, 0);
    522         SetConsoleMode(kk->win32.back, 0);
    523 
    524         GetConsoleCursorInfo(kk->win32.front, &cci);
    525         cci.dwSize = 0;
    526         cci.bVisible = FALSE;
    527         SetConsoleCursorInfo(kk->win32.front, &cci);
    528         SetConsoleCursorInfo(kk->win32.back, &cci);
    529 
    530         SetConsoleActiveScreenBuffer(kk->win32.front);
    531 
    532         kk->win32.buffer = malloc(kk->qq->width * kk->qq->height
    533                                    * sizeof(CHAR_INFO));
    534         if(kk->win32.buffer == NULL)
    535             return -1;
    536     }
    537     else
    538 #endif
    539 #if defined(USE_GL)
    540     if(kk->driver == CACA_DRIVER_GL)
    541     {
    542         char *empty_texture;
    543         char const *geometry;
    544         char *argv[2] = { "", NULL };
    545         unsigned int width = 0, height = 0;
    546         int argc = 1;
    547         int i;
    548 
    549         gl_kk = kk;
    550 
    551         geometry = getenv("CACA_GEOMETRY");
    552         if(geometry && *(geometry))
    553             sscanf(geometry, "%ux%u", &width, &height);
    554 
    555         if(width && height)
    556             cucul_set_size(kk->qq, width, height);
    557 
    558         kk->gl.font_width = 9;
    559         kk->gl.font_height = 15;
    560 
    561         kk->gl.width = kk->qq->width * kk->gl.font_width;
    562         kk->gl.height = kk->qq->height * kk->gl.font_height;
    563 
    564         kk->gl.resized = 0;
    565         kk->gl.bit = 0;
    566 
    567         kk->gl.mouse_changed = kk->gl.mouse_clicked = 0;
    568         kk->gl.mouse_button = kk->gl.mouse_state = 0;
    569 
    570         kk->gl.key = 0;
    571         kk->gl.special_key = 0;
    572 
    573         kk->gl.sw = 9.0f / 16.0f;
    574         kk->gl.sh = 15.0f / 16.0f;
    575 
    576         glutInit(&argc, argv);
    577 
    578         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    579         glutInitWindowSize(kk->gl.width, kk->gl.height);
    580         kk->gl.window = glutCreateWindow("caca for GL");
    581 
    582         gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
    583 
    584         glDisable(GL_CULL_FACE);
    585         glDisable(GL_DEPTH_TEST);
    586 
    587         glutKeyboardFunc(gl_handle_keyboard);
    588         glutSpecialFunc(gl_handle_special_key);
    589         glutReshapeFunc(gl_handle_reshape);
    590 
    591         glutMouseFunc(gl_handle_mouse);
    592         glutMotionFunc(gl_handle_mouse_motion);
    593         glutPassiveMotionFunc(gl_handle_mouse_motion);
    594 
    595         glLoadIdentity();
    596 
    597         glMatrixMode(GL_PROJECTION);
    598         glPushMatrix();
    599         glLoadIdentity();
    600         gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
    601 
    602         glMatrixMode(GL_MODELVIEW);
    603 
    604         glClear(GL_COLOR_BUFFER_BIT);
    605 
    606         empty_texture = malloc(16 * 16 * 4);
    607         if(empty_texture == NULL)
    608             return -1;
    609 
    610         memset(empty_texture, 0xff, 16 * 16 * 4);
    611         glEnable(GL_TEXTURE_2D);
    612 
    613         for(i = 0; i < 94; i++)
    614         {
    615             glGenTextures(1, (GLuint*)&kk->gl.id[i]);
    616             glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
    617             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    618             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    619             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8,
    620                          16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, empty_texture);
    621         }
    622 
    623         for(i = 0; i < 94; i++)
    624         {
    625             glDisable(GL_TEXTURE_2D);
    626             glClear(GL_COLOR_BUFFER_BIT);
    627 
    628             glColor3f(1, 1, 1);
    629             glRasterPos2f(0, 15);
    630             glutBitmapCharacter(GLUT_BITMAP_9_BY_15, i + 32);
    631 
    632             glEnable(GL_TEXTURE_2D);
    633             glBindTexture(GL_TEXTURE_2D, kk->gl.id[i]);
    634             glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
    635                              0, kk->gl.height - 16, 16, 16, 0);
    636 
    637             glutMainLoopEvent();
    638             glutPostRedisplay();
     244#else
     245            SLsmg_set_color(*attr++);
     246            SLsmg_write_char(*chars++ & 0x7f);
     247#endif
    639248        }
    640249    }
    641     else
    642 #endif
    643     {
    644         /* Dummy */
    645     }
    646 
    647     kk->delay = 0;
    648     kk->rendertime = 0;
    649 
    650     return 0;
    651 }
    652 
    653 int _caca_end_graphics(caca_t *kk)
    654 {
    655 #if defined(USE_SLANG)
    656     /* Nothing to do */
    657 #endif
    658 #if defined(USE_NCURSES)
    659     /* Nothing to do */
    660 #endif
    661 #if defined(USE_CONIO)
    662     if(kk->driver == CACA_DRIVER_CONIO)
    663     {
    664         free(kk->conio.screen);
    665     }
    666     else
    667 #endif
    668 #if defined(USE_X11)
    669     if(kk->driver == CACA_DRIVER_X11)
    670     {
    671         XSync(kk->x11.dpy, False);
    672 #if defined(HAVE_X11_XKBLIB_H)
    673         if(!kk->x11.autorepeat)
    674             XAutoRepeatOn(kk->x11.dpy);
    675 #endif
    676         XFreePixmap(kk->x11.dpy, kk->x11.pixmap);
    677         XFreeFont(kk->x11.dpy, kk->x11.font_struct);
    678         XFreeGC(kk->x11.dpy, kk->x11.gc);
    679         XUnmapWindow(kk->x11.dpy, kk->x11.window);
    680         XDestroyWindow(kk->x11.dpy, kk->x11.window);
    681         XCloseDisplay(kk->x11.dpy);
    682     }
    683     else
    684 #endif
    685 #if defined(USE_WIN32)
    686     if(kk->driver == CACA_DRIVER_WIN32)
    687     {
    688         SetConsoleActiveScreenBuffer(kk->win32.hout);
    689         CloseHandle(kk->win32.back);
    690         CloseHandle(kk->win32.front);
    691     }
    692     else
    693 #endif
    694 #if defined(USE_GL)
    695     if(kk->driver == CACA_DRIVER_GL)
    696     {
    697         glutDestroyWindow(kk->gl.window);
    698     }
    699     else
    700 #endif
    701     {
    702         /* Dummy */
    703     }
    704 
    705     return 0;
    706 }
    707 #endif /* _DOXYGEN_SKIP_ME */
    708 
    709 /** \brief Set the window title.
    710  *
    711  *  If libcaca runs in a window, try to change its title. This works with
    712  *  the X11 and Win32 drivers.
    713  *
    714  *  \param title The desired window title.
    715  *  \return 0 upon success, a non-zero value if an error occurs.
    716  */
    717 int caca_set_window_title(caca_t *kk, char const *title)
    718 {
    719 #if defined(USE_X11)
    720     if(kk->driver == CACA_DRIVER_X11)
    721     {
    722         XStoreName(kk->x11.dpy, kk->x11.window, title);
    723     }
    724     else
    725 #endif
    726 #if defined(USE_WIN32)
    727     if(kk->driver == CACA_DRIVER_WIN32)
    728     {
    729         SetConsoleTitle(title);
    730     }
    731     else
    732 #endif
    733 #if defined(USE_GL)
    734     if(kk->driver == CACA_DRIVER_GL)
    735     {
    736         glutSetWindowTitle(title);
    737     }
    738     else
    739 #endif
    740     {
    741         /* Not supported */
    742         return -1;
    743     }
    744 
    745     return 0;
    746 }
    747 
    748 /** \brief Get the window width.
    749  *
    750  *  If libcaca runs in a window, get the usable window width. This value can
    751  *  be used for aspect ratio calculation. If libcaca does not run in a window
    752  *  or if there is no way to know the font size, assume a 6x10 font is being
    753  *  used. Note that the units are not necessarily pixels.
    754  *
    755  *  \return The window width.
    756  */
    757 unsigned int caca_get_window_width(caca_t *kk)
    758 {
    759 #if defined(USE_X11)
    760     if(kk->driver == CACA_DRIVER_X11)
    761     {
    762         return kk->qq->width * kk->x11.font_width;
    763     }
    764     else
    765 #endif
    766 #if defined(USE_WIN32)
    767     if(kk->driver == CACA_DRIVER_WIN32)
    768     {
    769         /* FIXME */
    770     }
    771     else
    772 #endif
    773 #if defined(USE_GL)
    774     if(kk->driver == CACA_DRIVER_GL)
    775     {
    776         return kk->gl.width;
    777     }
    778     else
    779 #endif
    780     {
    781         /* Dummy */
    782     }
    783 
    784     /* Fallback to a 6x10 font */
    785     return kk->qq->width * 6;
    786 }
    787 
    788 /** \brief Get the window height.
    789  *
    790  *  If libcaca runs in a window, get the usable window height. This value can
    791  *  be used for aspect ratio calculation. If libcaca does not run in a window
    792  *  or if there is no way to know the font size, assume a 6x10 font is being
    793  *  used. Note that the units are not necessarily pixels.
    794  *
    795  *  \return The window height.
    796  */
    797 unsigned int caca_get_window_height(caca_t *kk)
    798 {
    799 #if defined(USE_X11)
    800     if(kk->driver == CACA_DRIVER_X11)
    801     {
    802         return kk->qq->height * kk->x11.font_height;
    803     }
    804     else
    805 #endif
    806 #if defined(USE_WIN32)
    807     if(kk->driver == CACA_DRIVER_WIN32)
    808     {
    809         /* FIXME */
    810     }
    811     else
    812 #endif
    813 #if defined(USE_GL)
    814     if(kk->driver == CACA_DRIVER_GL)
    815     {
    816         return kk->gl.height;
    817     }
    818     else
    819 #endif
    820     {
    821         /* Dummy */
    822     }
    823 
    824     /* Fallback to a 6x10 font */
    825     return kk->qq->height * 10;
    826 }
    827 
    828 /** \brief Set the refresh delay.
    829  *
    830  *  This function sets the refresh delay in microseconds. The refresh delay
    831  *  is used by caca_display() to achieve constant framerate. See the
    832  *  caca_display() documentation for more details.
    833  *
    834  *  If the argument is zero, constant framerate is disabled. This is the
    835  *  default behaviour.
    836  *
    837  *  \param usec The refresh delay in microseconds.
    838  */
    839 void caca_set_delay(caca_t *kk, unsigned int usec)
    840 {
    841     kk->delay = usec;
    842 }
    843 
    844 /** \brief Get the average rendering time.
    845  *
    846  *  This function returns the average rendering time, which is the average
    847  *  measured time between two caca_display() calls, in microseconds. If
    848  *  constant framerate was activated by calling caca_set_delay(), the average
    849  *  rendering time will not be considerably shorter than the requested delay
    850  *  even if the real rendering time was shorter.
    851  *
    852  *  \return The render time in microseconds.
    853  */
    854 unsigned int caca_get_rendertime(caca_t *kk)
    855 {
    856     return kk->rendertime;
    857 }
    858 
    859 /** \brief Flush pending changes and redraw the screen.
    860  *
    861  *  This function flushes all graphical operations and prints them to the
    862  *  screen. Nothing will show on the screen until caca_display() is
    863  *  called.
    864  *
    865  *  If caca_set_delay() was called with a non-zero value, caca_display()
    866  *  will use that value to achieve constant framerate: if two consecutive
    867  *  calls to caca_display() are within a time range shorter than the value
    868  *  set with caca_set_delay(), the second call will wait a bit before
    869  *  performing the screen refresh.
    870  */
    871 void caca_display(caca_t *kk)
    872 {
    873 #if !defined(_DOXYGEN_SKIP_ME)
    874 #define IDLE_USEC 10000
    875 #endif
    876     int ticks = kk->lastticks + _caca_getticks(&kk->timer);
    877 
    878 #if defined(USE_SLANG)
    879     if(kk->driver == CACA_DRIVER_SLANG)
    880     {
    881         int x, y;
    882         uint8_t *attr = kk->qq->attr;
    883         uint32_t *chars = kk->qq->chars;
    884         for(y = 0; y < (int)kk->qq->height; y++)
    885         {
    886             SLsmg_gotorc(y, 0);
    887             for(x = kk->qq->width; x--; )
    888             {
    889 #if defined(OPTIMISE_SLANG_PALETTE)
    890                 /* If foreground == background, just don't use this colour
    891                  * pair, and print a space instead of the real character. */
    892                 uint8_t fgcolor = *attr & 0xf;
    893                 uint8_t bgcolor = *attr >> 4;
    894                 if(fgcolor != bgcolor)
    895                 {
    896                     SLsmg_set_color(slang_assoc[*attr++]);
    897                     SLsmg_write_char(*chars++ & 0x7f);
    898                 }
    899                 else
    900                 {
    901                     if(fgcolor == CUCUL_COLOR_BLACK)
    902                         fgcolor = CUCUL_COLOR_WHITE;
    903                     else if(fgcolor == CUCUL_COLOR_WHITE
    904                              || fgcolor <= CUCUL_COLOR_LIGHTGRAY)
    905                         fgcolor = CUCUL_COLOR_BLACK;
    906                     else
    907                         fgcolor = CUCUL_COLOR_WHITE;
    908                     SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]);
    909                     SLsmg_write_char(' ');
    910                     chars++;
    911                     attr++;
    912                 }
    913 #else
    914                 SLsmg_set_color(*attr++);
    915                 SLsmg_write_char(*chars++ & 0x7f);
    916 #endif
    917             }
    918         }
    919         SLsmg_refresh();
    920     }
    921     else
    922 #endif
    923 #if defined(USE_NCURSES)
    924     if(kk->driver == CACA_DRIVER_NCURSES)
    925     {
    926         int x, y;
    927         uint8_t *attr = kk->qq->attr;
    928         uint32_t *chars = kk->qq->chars;
    929         for(y = 0; y < (int)kk->qq->height; y++)
    930         {
    931             move(y, 0);
    932             for(x = kk->qq->width; x--; )
    933             {
    934                 attrset(kk->ncurses.attr[*attr++]);
    935                 addch(*chars++ & 0x7f);
    936             }
    937         }
    938         refresh();
    939     }
    940     else
    941 #endif
    942 #if defined(USE_CONIO)
    943     if(kk->driver == CACA_DRIVER_CONIO)
    944     {
    945         int n;
    946         char *screen = kk->conio.screen;
    947         uint8_t *attr = kk->qq->attr;
    948         uint32_t *chars = kk->qq->chars;
    949         for(n = kk->qq->height * kk->qq->width; n--; )
    950         {
    951             *screen++ = *chars++ & 0x7f;
    952             *screen++ = *attr++;
    953         }
    954 #   if defined(SCREENUPDATE_IN_PC_H)
    955         ScreenUpdate(kk->conio.screen);
    956 #   else
    957         /* FIXME */
    958 #   endif
    959     }
    960     else
    961 #endif
    962 #if defined(USE_X11)
    963     if(kk->driver == CACA_DRIVER_X11)
    964     {
    965         unsigned int x, y, len;
    966 
    967         /* First draw the background colours. Splitting the process in two
    968          * loops like this is actually slightly faster. */
    969         for(y = 0; y < kk->qq->height; y++)
    970         {
    971             for(x = 0; x < kk->qq->width; x += len)
    972             {
    973                 uint8_t *attr = kk->qq->attr + x + y * kk->qq->width;
    974 
    975                 len = 1;
    976                 while(x + len < kk->qq->width
    977                        && (attr[len] >> 4) == (attr[0] >> 4))
    978                     len++;
    979 
    980                 XSetForeground(kk->x11.dpy, kk->x11.gc,
    981                                kk->x11.colors[attr[0] >> 4]);
    982                 XFillRectangle(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc,
    983                                x * kk->x11.font_width, y * kk->x11.font_height,
    984                                len * kk->x11.font_width, kk->x11.font_height);
    985             }
    986         }
    987 
    988         /* Then print the foreground characters */
    989         for(y = 0; y < kk->qq->height; y++)
    990         {
    991             for(x = 0; x < kk->qq->width; x += len)
    992             {
    993                 char buffer[BUFSIZ]; /* FIXME: use a smaller buffer */
    994                 uint32_t *chars = kk->qq->chars + x + y * kk->qq->width;
    995                 uint8_t *attr = kk->qq->attr + x + y * kk->qq->width;
    996 
    997                 len = 1;
    998 
    999                 /* Skip spaces */
    1000                 if(chars[0] == ' ')
    1001                     continue;
    1002 
    1003                 buffer[0] = chars[0] & 0x7f;
    1004 
    1005                 while(x + len < kk->qq->width
    1006                        && (attr[len] & 0xf) == (attr[0] & 0xf))
    1007                 {
    1008                     buffer[len] = chars[len] & 0x7f;
    1009                     len++;
    1010                 }
    1011 
    1012                 XSetForeground(kk->x11.dpy, kk->x11.gc, kk->x11.colors[attr[0] & 0xf]);
    1013                 XDrawString(kk->x11.dpy, kk->x11.pixmap, kk->x11.gc,
    1014                             x * kk->x11.font_width,
    1015                             (y + 1) * kk->x11.font_height - kk->x11.font_offset,
    1016                             buffer, len);
    1017             }
    1018         }
    1019 
    1020         XCopyArea(kk->x11.dpy, kk->x11.pixmap, kk->x11.window, kk->x11.gc, 0, 0,
    1021                   kk->qq->width * kk->x11.font_width, kk->qq->height * kk->x11.font_height,
    1022                   0, 0);
    1023         XFlush(kk->x11.dpy);
    1024     }
    1025     else
    1026 #endif
    1027 #if defined(USE_WIN32)
    1028     if(kk->driver == CACA_DRIVER_WIN32)
    1029     {
    1030         COORD size, pos;
    1031         SMALL_RECT rect;
    1032         unsigned int i;
    1033 
    1034         /* Render everything to our back buffer */
    1035         for(i = 0; i < kk->qq->width * kk->qq->height; i++)
    1036         {
    1037             kk->win32.buffer[i].Char.AsciiChar = kk->qq->chars[i] & 0x7f;
    1038             kk->win32.buffer[i].Attributes =
    1039                     win32_fg_palette[kk->qq->attr[i] & 0xf]
    1040                      | win32_bg_palette[kk->qq->attr[i] >> 4];
    1041         }
    1042 
    1043         /* Blit the back buffer to the front buffer */
    1044         size.X = kk->qq->width;
    1045         size.Y = kk->qq->height;
    1046         pos.X = pos.Y = 0;
    1047         rect.Left = rect.Top = 0;
    1048         rect.Right = kk->qq->width - 1;
    1049         rect.Bottom = kk->qq->height - 1;
    1050         WriteConsoleOutput(kk->win32.front, kk->win32.buffer, size, pos, &rect);
    1051     }
    1052     else
    1053 #endif
    1054 #if defined(USE_GL)
    1055     if(kk->driver == CACA_DRIVER_GL)
    1056     {
    1057         unsigned int x, y, line;
    1058 
    1059         glClear(GL_COLOR_BUFFER_BIT);
    1060 
    1061         line = 0;
    1062         for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
    1063         {
    1064             uint8_t *attr = kk->qq->attr + line * kk->qq->width;
    1065 
    1066             for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
    1067             {
    1068                 glDisable(GL_TEXTURE_2D);
    1069                 glColor4bv(gl_bgpal[attr[0] >> 4]);
    1070                 glBegin(GL_QUADS);
    1071                     glVertex2f(x, y);
    1072                     glVertex2f(x + kk->gl.font_width, y);
    1073                     glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height);
    1074                     glVertex2f(x, y + kk->gl.font_height);
    1075                 glEnd();
    1076 
    1077                 attr++;
    1078             }
    1079 
    1080             line++;
    1081         }
    1082 
    1083         /* 2nd pass, avoids changing render state too much */
    1084         glEnable(GL_BLEND);
    1085         glEnable(GL_TEXTURE_2D);
    1086         glBlendFunc(GL_ONE, GL_ONE);
    1087 
    1088         line = 0;
    1089         for(y = 0; y < kk->gl.height; y += kk->gl.font_height)
    1090         {
    1091             uint8_t *attr = kk->qq->attr + line * kk->qq->width;
    1092             uint32_t *chars = kk->qq->chars + line * kk->qq->width;
    1093 
    1094             for(x = 0; x < kk->gl.width; x += kk->gl.font_width)
    1095             {
    1096                 if(*chars != (uint32_t)' ')
    1097                 {
    1098                     char ch = *chars & 0x7f;
    1099 
    1100                     /* FIXME: check ch bounds */
    1101                     glBindTexture(GL_TEXTURE_2D, kk->gl.id[ch - 32]);
    1102                     glColor4bv(gl_bgpal[attr[0] & 0xf]);
    1103                     glBegin(GL_QUADS);
    1104                         glTexCoord2f(0, kk->gl.sh);
    1105                         glVertex2f(x, y);
    1106                         glTexCoord2f(kk->gl.sw, kk->gl.sh);
    1107                         glVertex2f(x + kk->gl.font_width, y);
    1108                         glTexCoord2f(kk->gl.sw, 0);
    1109                         glVertex2f(x + kk->gl.font_width, y + kk->gl.font_height);
    1110                         glTexCoord2f(0, 0);
    1111                         glVertex2f(x, y + kk->gl.font_height);
    1112                     glEnd();
    1113                 }
    1114 
    1115                 attr++;
    1116                 chars++;
    1117             }
    1118             line++;
    1119         }
    1120         glDisable(GL_BLEND);
    1121         glDisable(GL_TEXTURE_2D);
    1122 
    1123         glutMainLoopEvent();
    1124         glutSwapBuffers();
    1125         glutPostRedisplay();
    1126     }
    1127     else
    1128 #endif
    1129     {
    1130         /* Dummy */
    1131     }
    1132 
    1133     /* FIXME handle this somewhere else */
    1134     if(kk->resize)
    1135     {
    1136         kk->resize = 0;
    1137         caca_handle_resize(kk);
    1138     }
    1139 
    1140     /* Wait until kk->delay + time of last call */
    1141     ticks += _caca_getticks(&kk->timer);
    1142     for(ticks += _caca_getticks(&kk->timer);
    1143         ticks + IDLE_USEC < (int)kk->delay;
    1144         ticks += _caca_getticks(&kk->timer))
    1145     {
    1146         _caca_sleep(IDLE_USEC);
    1147     }
    1148 
    1149     /* Update the sliding mean of the render time */
    1150     kk->rendertime = (7 * kk->rendertime + ticks) / 8;
    1151 
    1152     kk->lastticks = ticks - kk->delay;
    1153 
    1154     /* If we drifted too much, it's bad, bad, bad. */
    1155     if(kk->lastticks > (int)kk->delay)
    1156         kk->lastticks = 0;
     250    SLsmg_refresh();
    1157251}
    1158252
     
    1161255 */
    1162256
    1163 static void caca_handle_resize(caca_t *kk)
     257void slang_handle_resize(caca_t *kk)
    1164258{
    1165259    unsigned int new_width, new_height;
     
    1168262    new_height = kk->qq->height;
    1169263
    1170 #if defined(USE_SLANG)
    1171     if(kk->driver == CACA_DRIVER_SLANG)
    1172     {
    1173         SLtt_get_screen_size();
    1174         new_width = SLtt_Screen_Cols;
    1175         new_height = SLtt_Screen_Rows;
    1176 
    1177         if(new_width != kk->qq->width || new_height != kk->qq->height)
    1178             SLsmg_reinit_smg();
    1179     }
    1180     else
    1181 #endif
    1182 #if defined(USE_NCURSES)
    1183     if(kk->driver == CACA_DRIVER_NCURSES)
    1184     {
    1185         struct winsize size;
    1186 
    1187         if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0)
    1188         {
    1189             new_width = size.ws_col;
    1190             new_height = size.ws_row;
    1191 #if defined(HAVE_RESIZE_TERM)
    1192             resize_term(new_height, new_width);
    1193 #else
    1194             resizeterm(new_height, new_width);
    1195 #endif
    1196             wrefresh(curscr);
    1197         }
    1198     }
    1199     else
    1200 #endif
    1201 #if defined(USE_CONIO)
    1202     if(kk->driver == CACA_DRIVER_CONIO)
    1203     {
    1204         /* Nothing to do here. */
    1205     }
    1206     else
    1207 #endif
    1208 #if defined(USE_X11)
    1209     if(kk->driver == CACA_DRIVER_X11)
    1210     {
    1211         Pixmap new_pixmap;
    1212 
    1213         new_width = kk->x11.new_width;
    1214         new_height = kk->x11.new_height;
    1215 
    1216         new_pixmap = XCreatePixmap(kk->x11.dpy, kk->x11.window,
    1217                                    kk->qq->width * kk->x11.font_width,
    1218                                    kk->qq->height * kk->x11.font_height,
    1219                                    DefaultDepth(kk->x11.dpy,
    1220                                                 DefaultScreen(kk->x11.dpy)));
    1221         XCopyArea(kk->x11.dpy, kk->x11.pixmap, new_pixmap, kk->x11.gc, 0, 0,
    1222                   kk->qq->width * kk->x11.font_width,
    1223                   kk->qq->height * kk->x11.font_height, 0, 0);
    1224         XFreePixmap(kk->x11.dpy, kk->x11.pixmap);
    1225         kk->x11.pixmap = new_pixmap;
    1226     }
    1227     else
    1228 #endif
    1229 #if defined(USE_WIN32)
    1230     if(kk->driver == CACA_DRIVER_WIN32)
    1231     {
    1232         /* Nothing to do here. */
    1233     }
    1234     else
    1235 #endif
    1236 #if defined(USE_GL)
    1237     if(kk->driver == CACA_DRIVER_GL)
    1238     {
    1239         kk->gl.width = kk->gl.new_width;
    1240         kk->gl.height = kk->gl.new_height;
    1241 
    1242         new_width = kk->gl.width / kk->gl.font_width;
    1243         new_height = (kk->gl.height / kk->gl.font_height) + 1;
    1244 
    1245         glMatrixMode(GL_PROJECTION);
    1246         glPushMatrix();
    1247         glLoadIdentity();
    1248 
    1249         glViewport(0, 0, kk->gl.width, kk->gl.height);
    1250         gluOrtho2D(0, kk->gl.width, kk->gl.height, 0);
    1251         glMatrixMode(GL_MODELVIEW);
    1252     }
    1253     else
    1254 #endif
    1255     {
    1256         /* Dummy */
    1257     }
    1258 
    1259     /* Tell libcucul we changed size */
     264    SLtt_get_screen_size();
     265    new_width = SLtt_Screen_Cols;
     266    new_height = SLtt_Screen_Rows;
     267
    1260268    if(new_width != kk->qq->width || new_height != kk->qq->height)
    1261         cucul_set_size(kk->qq, new_width, new_height);
    1262 }
    1263 
    1264 #if defined(USE_SLANG)
     269        SLsmg_reinit_smg();
     270}
     271
    1265272static void slang_init_palette(void)
    1266273{
     
    1305312#endif
    1306313}
     314
     315#if defined(HAVE_SIGNAL)
     316static RETSIGTYPE sigwinch_handler(int sig)
     317{
     318    sigwinch_kk->resize_event = 1;
     319
     320    signal(SIGWINCH, sigwinch_handler);;
     321}
     322#endif
     323
     324/*
     325 * Driver initialisation
     326 */
     327
     328void slang_init_driver(caca_t *kk)
     329{
     330    kk->driver.driver = CACA_DRIVER_SLANG;
     331
     332    kk->driver.init_graphics = slang_init_graphics;
     333    kk->driver.end_graphics = slang_end_graphics;
     334    kk->driver.set_window_title = slang_set_window_title;
     335    kk->driver.get_window_width = slang_get_window_width;
     336    kk->driver.get_window_height = slang_get_window_height;
     337    kk->driver.display = slang_display;
     338    kk->driver.handle_resize = slang_handle_resize;
     339}
     340
    1307341#endif /* USE_SLANG */
    1308342
    1309 #if defined(USE_X11)
    1310 static int x11_error_handler(Display *dpy, XErrorEvent *event)
    1311 {
    1312     /* Ignore the error */
    1313     return 0;
    1314 }
    1315 #endif
    1316 
    1317 #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
    1318 static RETSIGTYPE sigwinch_handler(int sig)
    1319 {
    1320     sigwinch_kk->resize_event = 1;
    1321 
    1322     signal(SIGWINCH, sigwinch_handler);;
    1323 }
    1324 #endif
    1325 
    1326 #if defined(USE_GL)
    1327 static void gl_handle_keyboard(unsigned char key, int x, int y)
    1328 {
    1329     caca_t *kk = gl_kk;
    1330 
    1331     kk->gl.key = key;
    1332 }
    1333 
    1334 static void gl_handle_special_key(int key, int x, int y)
    1335 {
    1336     caca_t *kk = gl_kk;
    1337 
    1338     kk->gl.special_key = key;
    1339 }
    1340 
    1341 static void gl_handle_reshape(int w, int h)
    1342 {
    1343     caca_t *kk = gl_kk;
    1344 
    1345     if(kk->gl.bit) /* Do not handle reshaping at the first time */
    1346     {
    1347         kk->gl.new_width = w;
    1348         kk->gl.new_height = h;
    1349 
    1350         kk->gl.resized = 1;
    1351     }
    1352     else
    1353         kk->gl.bit = 1;
    1354 }
    1355 
    1356 static void gl_handle_mouse(int button, int state, int x, int y)
    1357 {
    1358     caca_t *kk = gl_kk;
    1359 
    1360     kk->gl.mouse_clicked = 1;
    1361     kk->gl.mouse_butt