source: libcaca/trunk/src/graphics.c @ 466

Last change on this file since 466 was 466, checked in by Sam Hocevar, 17 years ago
  • compilation fix.
  • Property svn:keywords set to Id
File size: 39.3 KB
Line 
1/*
2 *  libcaca       ASCII-Art library
3 *  Copyright (c) 2002, 2003 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  This library is free software; you can redistribute it and/or
7 *  modify it under the terms of the GNU Lesser General Public
8 *  License as published by the Free Software Foundation; either
9 *  version 2 of the License, or (at your option) any later version.
10 *
11 *  This library is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 *  Lesser General Public License for more details.
15 *
16 *  You should have received a copy of the GNU Lesser General Public
17 *  License along with this library; if not, write to the Free Software
18 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 *  02111-1307  USA
20 */
21
22/** \file graphics.c
23 *  \version \$Id: graphics.c 466 2005-01-22 16:43:58Z sam $
24 *  \author Sam Hocevar <sam@zoy.org>
25 *  \brief Character drawing
26 *
27 *  This file contains character and string drawing functions.
28 */
29
30#include "config.h"
31
32#if defined(USE_SLANG)
33#   if defined(HAVE_SLANG_SLANG_H)
34#       include <slang/slang.h>
35#   else
36#       include <slang.h>
37#   endif
38#endif
39#if defined(USE_NCURSES)
40#   if defined(HAVE_NCURSES_H)
41#       include <ncurses.h>
42#   else
43#       include <curses.h>
44#   endif
45#endif
46#if defined(USE_CONIO)
47#   include <conio.h>
48#   if defined(SCREENUPDATE_IN_PC_H)
49#       include <pc.h>
50#   endif
51#endif
52#if defined(USE_X11)
53#   include <X11/Xlib.h>
54#   if defined(HAVE_X11_XKBLIB_H)
55#       include <X11/XKBlib.h>
56#   endif
57#endif
58#if defined(USE_WIN32)
59#   include <windows.h>
60#endif
61
62#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME)
63#   include <inttypes.h>
64#else
65typedef unsigned char uint8_t;
66#endif
67
68#include <stdio.h> /* BUFSIZ */
69#include <string.h>
70#include <stdlib.h>
71#if defined(HAVE_UNISTD_H)
72#   include <unistd.h>
73#endif
74#include <stdarg.h>
75
76#if defined(HAVE_SIGNAL_H)
77#   include <signal.h>
78#endif
79#if defined(HAVE_SYS_IOCTL_H)
80#   include <sys/ioctl.h>
81#endif
82
83#include "caca.h"
84#include "caca_internals.h"
85
86/*
87 * Global variables
88 */
89#if !defined(_DOXYGEN_SKIP_ME)
90unsigned int _caca_width = 0;
91unsigned int _caca_height = 0;
92int _caca_resize = 0;
93int _caca_resize_event = 0;
94#endif
95
96/*
97 * Local variables
98 */
99#if !defined(_DOXYGEN_SKIP_ME)
100static uint8_t *cache_char, *cache_attr;
101#endif
102
103#if defined(USE_NCURSES)
104static int ncurses_attr[16*16];
105#endif
106
107#if defined(USE_SLANG)
108/* Tables generated by test/optipal.c */
109static int const slang_palette[2*16*16] =
110{
111     1,  0,   2,  0,   3,  0,   4,  0,   5,  0,   6,  0,   7,  0,   8,  0,
112     9,  0,  10,  0,  11,  0,  12,  0,  13,  0,  14,  0,  15,  0,   0,  8,
113     8,  7,   7,  8,  15,  7,   7, 15,  15,  9,   9, 15,   1,  9,   9,  1,
114     7,  9,   9,  7,   8,  1,   1,  8,   0,  1,  15, 10,  10, 15,   2, 10,
115    10,  2,   7, 10,  10,  7,   8,  2,   2,  8,   0,  2,  15, 11,  11, 15,
116     3, 11,  11,  3,   7, 11,  11,  7,   8,  3,   3,  8,   0,  3,  15, 12,
117    12, 15,   4, 12,  12,  4,   7, 12,  12,  7,   8,  4,   4,  8,   0,  4,
118    15, 13,  13, 15,   5, 13,  13,  5,   7, 13,  13,  7,   8,  5,   5,  8,
119     0,  5,  15, 14,  14, 15,   6, 14,  14,  6,   7, 14,  14,  7,   8,  6,
120     6,  8,   0,  6,   4,  6,   6,  4,  12, 14,  14, 12,   6,  2,   2,  6,
121    14, 10,  10, 14,   2,  3,   3,  2,  10, 11,  11, 10,   3,  1,   1,  3,
122    11,  9,   9, 11,   1,  5,   5,  1,   9, 13,  13,  9,   5,  4,   4,  5,
123    13, 12,  12, 13,   4, 14,   6, 12,  12,  6,  14,  4,   6, 10,   2, 14,
124    14,  2,  10,  6,   2, 11,   3, 10,  10,  3,  11,  2,   3,  9,   1, 11,
125    11,  1,   9,  3,   1, 13,   5,  9,   9,  5,  13,  1,   5, 12,   4, 13,
126    13,  4,  12,  5,   0,  7,   0, 15,  15,  8,   8, 15,  15,  1,   7,  1,
127     1,  6,   2,  5,   3,  4,   4,  3,   5,  2,   6,  1,   0,  0,   1,  1,
128     9,  6,  10,  5,  11,  4,  12,  3,  13,  2,  14,  1,   2,  2,   3,  3,
129     4,  4,   5,  5,   6,  6,   7,  7,  14,  9,   1, 15,   8,  9,   8,  8,
130     9,  9,   1,  7,   0,  9,   9,  8,   6,  9,  13, 10,   2, 15,   8, 10,
131     7,  2,  15,  2,   2,  7,   0, 10,  10,  8,   5, 10,  12, 11,   3, 15,
132     8, 11,   7,  3,  15,  3,   3,  7,   0, 11,  11,  8,   4, 11,  11, 12,
133     4, 15,   8, 12,   7,  4,  15,  4,   4,  7,   0, 12,  12,  8,   3, 12,
134    10, 13,   5, 15,   8, 13,   7,  5,  15,  5,   5,  7,   0, 13,  13,  8,
135     2, 13,   9, 14,   6, 15,   8, 14,   7,  6,  15,  6,   6,  7,   0, 14,
136    14,  8,   1, 14,   5,  6,   2,  4,  13, 14,  10, 12,   4,  2,   3,  6,
137    12, 10,  11, 14,   6,  3,   1,  2,  14, 11,   9, 10,   2,  1,   5,  3,
138    10,  9,  13, 11,   3,  5,   4,  1,  11, 13,  12,  9,   1,  4,   6,  5,
139     9, 12,  14, 13,   5, 14,   2, 12,  13,  6,  10,  4,   4, 10,   3, 14,
140    12,  2,  11,  6,   6, 11,   1, 10,  14,  3,   9,  2,   2,  9,   5, 11,
141    10,  1,  13,  3,   3, 13,   4,  9,  11,  5,  12,  1,   1, 12,   6, 13,
142     9,  4,  14,  5,  10, 10,  11, 11,  12, 12,  13, 13,  14, 14,  15, 15,
143};
144
145static int const slang_assoc[16*16] =
146{
147    134, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
148    28, 135, 214, 86, 219, 91, 133, 127, 26, 23, 240, 112, 245, 117, 141, 126,
149    37, 211, 142, 83, 206, 132, 78, 160, 35, 237, 32, 109, 232, 140, 104, 161,
150    46, 87, 82, 143, 131, 215, 210, 169, 44, 113, 108, 41, 139, 241, 236, 170,
151    55, 222, 203, 130, 144, 94, 75, 178, 53, 248, 229, 138, 50, 120, 101, 179,
152    64, 90, 129, 218, 95, 145, 223, 187, 62, 116, 137, 244, 121, 59, 249, 188,
153    73, 128, 79, 207, 74, 202, 146, 196, 71, 136, 105, 233, 100, 228, 68, 197,
154    122, 153, 162, 171, 180, 189, 198, 147, 16, 25, 34, 43, 52, 61, 70, 18,
155    15, 27, 36, 45, 54, 63, 72, 17, 151, 155, 164, 173, 182, 191, 200, 124,
156    154, 22, 238, 110, 243, 115, 156, 24, 150, 152, 216, 88, 221, 93, 148, 20,
157    163, 235, 31, 107, 230, 165, 102, 33, 159, 213, 250, 85, 208, 157, 80, 29,
158    172, 111, 106, 40, 174, 239, 234, 42, 168, 89, 84, 251, 166, 217, 212, 38,
159    181, 246, 227, 183, 49, 118, 99, 51, 177, 224, 205, 175, 252, 96, 77, 47,
160    190, 114, 192, 242, 119, 58, 247, 60, 186, 92, 184, 220, 97, 253, 225, 56,
161    199, 201, 103, 231, 98, 226, 67, 69, 195, 193, 81, 209, 76, 204, 254, 65,
162    123, 149, 158, 167, 176, 185, 194, 19, 125, 21, 30, 39, 48, 57, 66, 255,
163};
164#endif
165
166#if defined(USE_CONIO)
167static struct text_info conio_ti;
168static char *conio_screen;
169#endif
170
171#if defined(USE_X11) && !defined(_DOXYGEN_SKIP_ME)
172Display *x11_dpy;
173Window x11_window;
174Pixmap x11_pixmap;
175GC x11_gc;
176long int x11_event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask
177            | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask
178            | ExposureMask;
179int x11_font_width, x11_font_height;
180unsigned int x11_new_width, x11_new_height;
181static int x11_colors[16];
182static Font x11_font;
183static XFontStruct *x11_font_struct;
184static int x11_font_offset;
185#if defined(HAVE_X11_XKBLIB_H)
186static Bool x11_detect_autorepeat;
187#endif
188#endif
189
190#if defined(USE_WIN32)
191HANDLE win32_hin, win32_hout;
192static HANDLE win32_front, win32_back;
193static CHAR_INFO *win32_buffer;
194
195static int const win32_fg_palette[] =
196{
197    0,
198    FOREGROUND_BLUE,
199    FOREGROUND_GREEN,
200    FOREGROUND_GREEN | FOREGROUND_BLUE,
201    FOREGROUND_RED,
202    FOREGROUND_RED | FOREGROUND_BLUE,
203    FOREGROUND_RED | FOREGROUND_GREEN,
204    FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
205    FOREGROUND_INTENSITY,
206    FOREGROUND_INTENSITY | FOREGROUND_BLUE,
207    FOREGROUND_INTENSITY | FOREGROUND_GREEN,
208    FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE,
209    FOREGROUND_INTENSITY | FOREGROUND_RED,
210    FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE,
211    FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN,
212    FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
213};
214
215static int const win32_bg_palette[] =
216{
217    0,
218    BACKGROUND_BLUE,
219    BACKGROUND_GREEN,
220    BACKGROUND_GREEN | BACKGROUND_BLUE,
221    BACKGROUND_RED,
222    BACKGROUND_RED | BACKGROUND_BLUE,
223    BACKGROUND_RED | BACKGROUND_GREEN,
224    BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
225    BACKGROUND_INTENSITY,
226    BACKGROUND_INTENSITY | BACKGROUND_BLUE,
227    BACKGROUND_INTENSITY | BACKGROUND_GREEN,
228    BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE,
229    BACKGROUND_INTENSITY | BACKGROUND_RED,
230    BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE,
231    BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN,
232    BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
233};
234#endif
235
236static char *_caca_empty_line;
237static char *_caca_scratch_line;
238
239static unsigned int _caca_delay;
240static unsigned int _caca_rendertime;
241
242#if defined(OPTIMISE_SLANG_PALETTE)
243static int _caca_fgisbg = 0;
244#endif
245static enum caca_color _caca_fgcolor = CACA_COLOR_LIGHTGRAY;
246static enum caca_color _caca_bgcolor = CACA_COLOR_BLACK;
247
248/*
249 * Local functions
250 */
251static void caca_handle_resize(void);
252
253#if defined(USE_SLANG)
254static void slang_init_palette(void);
255#endif
256
257#if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
258static RETSIGTYPE sigwinch_handler(int);
259#endif
260
261#if defined(USE_X11)
262static int x11_error_handler(Display *, XErrorEvent *);
263#endif
264
265/** \brief Set the default colour pair.
266 *
267 *  This function sets the default colour pair. String functions such as
268 *  caca_printf() and graphical primitive functions such as caca_draw_line()
269 *  will use these colour pairs.
270 *
271 *  \param fgcolor The requested foreground colour.
272 *  \param bgcolor The requested background colour.
273 */
274void caca_set_color(enum caca_color fgcolor, enum caca_color bgcolor)
275{
276    if(fgcolor < 0 || fgcolor > 15 || bgcolor < 0 || bgcolor > 15)
277        return;
278
279    _caca_fgcolor = fgcolor;
280    _caca_bgcolor = bgcolor;
281
282    switch(_caca_driver)
283    {
284#if defined(USE_SLANG)
285    case CACA_DRIVER_SLANG:
286
287#if defined(OPTIMISE_SLANG_PALETTE)
288        /* If foreground == background, discard this colour pair. Functions
289         * such as caca_putchar will print spaces instead of characters */
290        if(fgcolor != bgcolor)
291            _caca_fgisbg = 0;
292        else
293        {
294            _caca_fgisbg = 1;
295            if(fgcolor == CACA_COLOR_BLACK)
296                fgcolor = CACA_COLOR_WHITE;
297            else if(fgcolor == CACA_COLOR_WHITE
298                     || fgcolor <= CACA_COLOR_LIGHTGRAY)
299                fgcolor = CACA_COLOR_BLACK;
300            else
301                fgcolor = CACA_COLOR_WHITE;
302        }
303#endif
304
305#if defined(OPTIMISE_SLANG_PALETTE)
306        SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]);
307#else
308        SLsmg_set_color(fgcolor + 16 * bgcolor);
309#endif
310        break;
311#endif
312#if defined(USE_NCURSES)
313    case CACA_DRIVER_NCURSES:
314        attrset(ncurses_attr[fgcolor + 16 * bgcolor]);
315        break;
316#endif
317#if defined(USE_CONIO)
318    case CACA_DRIVER_CONIO:
319        textbackground(bgcolor);
320        textcolor(fgcolor);
321        break;
322#endif
323#if defined(USE_X11)
324    case CACA_DRIVER_X11:
325        /* Nothing to do */
326        break;
327#endif
328#if defined(USE_WIN32)
329    case CACA_DRIVER_WIN32:
330        /* Nothing to do */
331        break;
332#endif
333    default:
334        break;
335    }
336}
337
338/** \brief Get the current foreground colour.
339 *
340 *  This function returns the current foreground colour that was set with
341 *  caca_set_color().
342 *
343 *  \return The current foreground colour.
344 */
345enum caca_color caca_get_fg_color(void)
346{
347    return _caca_fgcolor;
348}
349
350/** \brief Get the current background colour.
351 *
352 *  This function returns the current background colour that was set with
353 *  caca_set_color().
354 *
355 *  \return The current background colour.
356 */
357enum caca_color caca_get_bg_color(void)
358{
359    return _caca_bgcolor;
360}
361
362/** \brief Print a character.
363 *
364 *  This function prints a character at the given coordinates, using the
365 *  default foreground and background values. If the coordinates are outside
366 *  the screen boundaries, nothing is printed.
367 *
368 *  \param x X coordinate.
369 *  \param y Y coordinate.
370 *  \param c The character to print.
371 */
372void caca_putchar(int x, int y, char c)
373{
374#if defined(USE_CONIO)
375    char *data;
376#endif
377    if(x < 0 || x >= (int)_caca_width ||
378       y < 0 || y >= (int)_caca_height)
379        return;
380
381    cache_char[x + y * _caca_width] = c;
382    cache_attr[x + y * _caca_width] = (_caca_bgcolor << 4) | _caca_fgcolor;
383
384    switch(_caca_driver)
385    {
386#if defined(USE_SLANG)
387    case CACA_DRIVER_SLANG:
388        SLsmg_gotorc(y, x);
389#if defined(OPTIMISE_SLANG_PALETTE)
390        if(_caca_fgisbg)
391            SLsmg_write_char(' ');
392        else
393#endif
394            SLsmg_write_char(c);
395        break;
396#endif
397#if defined(USE_NCURSES)
398    case CACA_DRIVER_NCURSES:
399        move(y, x);
400        addch(c);
401        break;
402#endif
403#if defined(USE_CONIO)
404    case CACA_DRIVER_CONIO:
405        data = conio_screen + 2 * (x + y * _caca_width);
406        data[0] = c;
407        data[1] = (_caca_bgcolor << 4) | _caca_fgcolor;
408        break;
409#endif
410#if defined(USE_X11)
411    case CACA_DRIVER_X11:
412        break;
413#endif
414#if defined(USE_WIN32)
415    case CACA_DRIVER_WIN32:
416        break;
417#endif
418    default:
419        break;
420    }
421}
422
423/** \brief Print a string.
424 *
425 *  This function prints a string at the given coordinates, using the
426 *  default foreground and background values. The coordinates may be outside
427 *  the screen boundaries (eg. a negative Y coordinate) and the string will
428 *  be cropped accordingly if it is too long.
429 *
430 *  \param x X coordinate.
431 *  \param y Y coordinate.
432 *  \param s The string to print.
433 */
434void caca_putstr(int x, int y, char const *s)
435{
436    char *charbuf;
437    char *attrbuf;
438    char const *t;
439    unsigned int len;
440
441    if(y < 0 || y >= (int)_caca_height || x >= (int)_caca_width)
442        return;
443
444    len = strlen(s);
445
446    if(x < 0)
447    {
448        if(len < (unsigned int)-x)
449            return;
450        len -= -x;
451        s += -x;
452        x = 0;
453    }
454
455    if(x + len >= _caca_width)
456    {
457        len = _caca_width - x;
458        memcpy(_caca_scratch_line, s, len);
459        _caca_scratch_line[len] = '\0';
460        s = _caca_scratch_line;
461    }
462
463    charbuf = cache_char + x + y * _caca_width;
464    attrbuf = cache_attr + x + y * _caca_width;
465    t = s;
466    while(*t)
467    {
468        *charbuf++ = *t++;
469        *attrbuf++ = (_caca_bgcolor << 4) | _caca_fgcolor;
470    }
471
472    switch(_caca_driver)
473    {
474#if defined(USE_SLANG)
475    case CACA_DRIVER_SLANG:
476        SLsmg_gotorc(y, x);
477#if defined(OPTIMISE_SLANG_PALETTE)
478        if(_caca_fgisbg)
479            SLsmg_write_string(_caca_empty_line + _caca_width - len);
480        else
481#endif
482        {
483            union { char *ch; const char *constch; } u;
484            u.constch = s;
485            SLsmg_write_string(u.ch);
486        }
487        break;
488#endif
489#if defined(USE_NCURSES)
490    case CACA_DRIVER_NCURSES:
491        move(y, x);
492        addstr(s);
493        break;
494#endif
495#if defined(USE_CONIO)
496    case CACA_DRIVER_CONIO:
497        charbuf = conio_screen + 2 * (x + y * _caca_width);
498        while(*s)
499        {
500            *charbuf++ = *s++;
501            *charbuf++ = (_caca_bgcolor << 4) | _caca_fgcolor;
502        }
503        break;
504#endif
505#if defined(USE_X11)
506    case CACA_DRIVER_X11:
507        break;
508#endif
509#if defined(USE_WIN32)
510    case CACA_DRIVER_WIN32:
511        break;
512#endif
513    default:
514        break;
515    }
516}
517
518/** \brief Format a string.
519 *
520 *  This function formats a string at the given coordinates, using the
521 *  default foreground and background values. The coordinates may be outside
522 *  the screen boundaries (eg. a negative Y coordinate) and the string will
523 *  be cropped accordingly if it is too long. The syntax of the format
524 *  string is the same as for the C printf() function.
525 *
526 *  \param x X coordinate.
527 *  \param y Y coordinate.
528 *  \param format The format string to print.
529 *  \param ... Arguments to the format string.
530 */
531void caca_printf(int x, int y, char const *format, ...)
532{
533    char tmp[BUFSIZ];
534    char *buf = tmp;
535    va_list args;
536
537    if(y < 0 || y >= (int)_caca_height || x >= (int)_caca_width)
538        return;
539
540    if(_caca_width - x + 1 > BUFSIZ)
541        buf = malloc(_caca_width - x + 1);
542
543    va_start(args, format);
544#if defined(HAVE_VSNPRINTF)
545    vsnprintf(buf, _caca_width - x + 1, format, args);
546#else
547    vsprintf(buf, format, args);
548#endif
549    buf[_caca_width - x] = '\0';
550    va_end(args);
551
552    caca_putstr(x, y, buf);
553
554    if(buf != tmp)
555        free(buf);
556}
557
558/** \brief Get the screen.
559 *
560 *  This function fills a byte array with the character values.
561 */
562void caca_get_screen(char *buffer)
563{
564    unsigned int x, y;
565
566    for(y = 0; y < _caca_height; y++)
567    {
568        for(x = 0; x < _caca_width; x++)
569        {
570            *buffer++ = cache_attr[x + y * _caca_width];
571            *buffer++ = cache_char[x + y * _caca_width];
572        }
573    }
574}
575
576/** \brief Clear the screen.
577 *
578 *  This function clears the screen using a black background.
579 */
580void caca_clear(void)
581{
582    enum caca_color oldfg = caca_get_fg_color();
583    enum caca_color oldbg = caca_get_bg_color();
584    int y = _caca_height;
585
586    caca_set_color(CACA_COLOR_LIGHTGRAY, CACA_COLOR_BLACK);
587
588    /* We could use SLsmg_cls() etc., but drawing empty lines is much faster */
589    while(y--)
590        caca_putstr(0, y, _caca_empty_line);
591
592    caca_set_color(oldfg, oldbg);
593}
594
595#if !defined(_DOXYGEN_SKIP_ME)
596int _caca_init_graphics(void)
597{
598#if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
599    signal(SIGWINCH, sigwinch_handler);
600#endif
601
602#if defined(USE_SLANG)
603    if(_caca_driver == CACA_DRIVER_SLANG)
604    {
605        slang_init_palette();
606
607        /* Disable alt charset support so that we get a chance to have all
608         * 256 colour pairs */
609        SLtt_Has_Alt_Charset = 0;
610
611        _caca_width = SLtt_Screen_Cols;
612        _caca_height = SLtt_Screen_Rows;
613    }
614    else
615#endif
616#if defined(USE_NCURSES)
617    if(_caca_driver == CACA_DRIVER_NCURSES)
618    {
619        static int curses_colors[] =
620        {
621            /* Standard curses colours */
622            COLOR_BLACK,
623            COLOR_BLUE,
624            COLOR_GREEN,
625            COLOR_CYAN,
626            COLOR_RED,
627            COLOR_MAGENTA,
628            COLOR_YELLOW,
629            COLOR_WHITE,
630            /* Extra values for xterm-16color */
631            COLOR_BLACK + 8,
632            COLOR_BLUE + 8,
633            COLOR_GREEN + 8,
634            COLOR_CYAN + 8,
635            COLOR_RED + 8,
636            COLOR_MAGENTA + 8,
637            COLOR_YELLOW + 8,
638            COLOR_WHITE + 8
639        };
640
641        int fg, bg, max;
642
643        /* Activate colour */
644        start_color();
645
646        /* If COLORS == 16, it means the terminal supports full bright colours
647         * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
648         * we can build 16*16 colour pairs.
649         * If COLORS == 8, it means the terminal does not know about bright
650         * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
651         * and \e[5m). We can only build 8*8 colour pairs. */
652        max = COLORS >= 16 ? 16 : 8;
653
654        for(bg = 0; bg < max; bg++)
655            for(fg = 0; fg < max; fg++)
656            {
657                /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
658                 * is light gray on black, since some terminals don't like
659                 * this colour pair to be redefined. */
660                int col = ((max + 7 - fg) % max) + max * bg;
661                init_pair(col, curses_colors[fg], curses_colors[bg]);
662                ncurses_attr[fg + 16 * bg] = COLOR_PAIR(col);
663
664                if(max == 8)
665                {
666                    /* Bright fg on simple bg */
667                    ncurses_attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
668                    /* Simple fg on bright bg */
669                    ncurses_attr[fg + 16 * (bg + 8)] = A_BLINK
670                                                        | COLOR_PAIR(col);
671                    /* Bright fg on bright bg */
672                    ncurses_attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
673                                                            | COLOR_PAIR(col);
674                }
675            }
676
677        _caca_width = COLS;
678        _caca_height = LINES;
679    }
680    else
681#endif
682#if defined(USE_CONIO)
683    if(_caca_driver == CACA_DRIVER_CONIO)
684    {
685        gettextinfo(&conio_ti);
686        conio_screen = malloc(2 * conio_ti.screenwidth
687                                 * conio_ti.screenheight * sizeof(char));
688        if(conio_screen == NULL)
689            return -1;
690#   if defined(SCREENUPDATE_IN_PC_H)
691        ScreenRetrieve(conio_screen);
692#   else
693        /* FIXME */
694#   endif
695        _caca_width = conio_ti.screenwidth;
696        _caca_height = conio_ti.screenheight;
697    }
698    else
699#endif
700#if defined(USE_X11)
701    if(_caca_driver == CACA_DRIVER_X11)
702    {
703        static int x11_palette[] =
704        {
705            /* Standard curses colours */
706            0x0,    0x0,    0x0,
707            0x0,    0x0,    0x8000,
708            0x0,    0x8000, 0x0,
709            0x0,    0x8000, 0x8000,
710            0x8000, 0x0,    0x0,
711            0x8000, 0x0,    0x8000,
712            0x8000, 0x8000, 0x0,
713            0x8000, 0x8000, 0x8000,
714            /* Extra values for xterm-16color */
715            0x4000, 0x4000, 0x4000,
716            0x4000, 0x4000, 0xffff,
717            0x4000, 0xffff, 0x4000,
718            0x4000, 0xffff, 0xffff,
719            0xffff, 0x4000, 0x4000,
720            0xffff, 0x4000, 0xffff,
721            0xffff, 0xffff, 0x4000,
722            0xffff, 0xffff, 0xffff,
723        };
724
725        Colormap colormap;
726        XSetWindowAttributes x11_winattr;
727        int (*old_error_handler)(Display *, XErrorEvent *);
728        char const *font_name = "8x13bold";
729        int i;
730
731        if(getenv("CACA_GEOMETRY") && *(getenv("CACA_GEOMETRY")))
732            sscanf(getenv("CACA_GEOMETRY"),
733                   "%ux%u", &_caca_width, &_caca_height);
734
735        if(!_caca_width)
736            _caca_width = 80;
737        if(!_caca_height)
738            _caca_height = 32;
739
740        x11_dpy = XOpenDisplay(NULL);
741        if(x11_dpy == NULL)
742            return -1;
743
744        if(getenv("CACA_FONT") && *(getenv("CACA_FONT")))
745            font_name = getenv("CACA_FONT");
746
747        /* Ignore font errors */
748        old_error_handler = XSetErrorHandler(x11_error_handler);
749
750        x11_font = XLoadFont(x11_dpy, font_name);
751        if(!x11_font)
752        {
753            XCloseDisplay(x11_dpy);
754            return -1;
755        }
756
757        x11_font_struct = XQueryFont(x11_dpy, x11_font);
758        if(!x11_font_struct)
759        {
760            XUnloadFont(x11_dpy, x11_font);
761            XCloseDisplay(x11_dpy);
762            return -1;
763        }
764
765        /* Reset the default X11 error handler */
766        XSetErrorHandler(old_error_handler);
767
768        x11_font_width = x11_font_struct->max_bounds.width;
769        x11_font_height = x11_font_struct->max_bounds.ascent
770                             + x11_font_struct->max_bounds.descent;
771        x11_font_offset = x11_font_struct->max_bounds.descent;
772
773        colormap = DefaultColormap(x11_dpy, DefaultScreen(x11_dpy));
774        for(i = 0; i < 16; i++)
775        {
776            XColor color;
777            color.red = x11_palette[i * 3];
778            color.green = x11_palette[i * 3 + 1];
779            color.blue = x11_palette[i * 3 + 2];
780            XAllocColor(x11_dpy, colormap, &color);
781            x11_colors[i] = color.pixel;
782        }
783
784        x11_winattr.backing_store = Always;
785        x11_winattr.background_pixel = x11_colors[0];
786        x11_winattr.event_mask = ExposureMask | StructureNotifyMask;
787
788        x11_window = XCreateWindow(x11_dpy, DefaultRootWindow(x11_dpy), 0, 0,
789                                   _caca_width * x11_font_width,
790                                   _caca_height * x11_font_height,
791                                   0, 0, InputOutput, 0,
792                                   CWBackingStore | CWBackPixel | CWEventMask,
793                                   &x11_winattr);
794
795        XStoreName(x11_dpy, x11_window, "caca for X");
796
797        XSelectInput(x11_dpy, x11_window, StructureNotifyMask);
798        XMapWindow(x11_dpy, x11_window);
799
800        x11_gc = XCreateGC(x11_dpy, x11_window, 0, NULL);
801        XSetForeground(x11_dpy, x11_gc, x11_colors[15]);
802        XSetFont(x11_dpy, x11_gc, x11_font);
803
804        for(;;)
805        {
806            XEvent event;
807            XNextEvent(x11_dpy, &event);
808            if (event.type == MapNotify)
809                break;
810        }
811
812        /* Disable autorepeat */
813#if defined(HAVE_X11_XKBLIB_H)
814        XkbSetDetectableAutoRepeat(x11_dpy, True, &x11_detect_autorepeat);
815        if(!x11_detect_autorepeat)
816            XAutoRepeatOff(x11_dpy);
817#endif
818
819        XSelectInput(x11_dpy, x11_window, x11_event_mask);
820
821        XSync(x11_dpy, False);
822
823        x11_pixmap = XCreatePixmap(x11_dpy, x11_window,
824                                   _caca_width * x11_font_width,
825                                   _caca_height * x11_font_height,
826                                   DefaultDepth(x11_dpy,
827                                                DefaultScreen(x11_dpy)));
828
829        x11_new_width = x11_new_height = 0;
830    }
831    else
832#endif
833#if defined(USE_WIN32)
834    if(_caca_driver == CACA_DRIVER_WIN32)
835    {
836        CONSOLE_CURSOR_INFO cci;
837        CONSOLE_SCREEN_BUFFER_INFO csbi;
838        COORD size;
839
840        win32_front = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
841                                                0, NULL,
842                                                CONSOLE_TEXTMODE_BUFFER, NULL);
843        if(!win32_front || win32_front == INVALID_HANDLE_VALUE)
844            return -1;
845
846        win32_back = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
847                                               0, NULL,
848                                               CONSOLE_TEXTMODE_BUFFER, NULL);
849        if(!win32_back || win32_back == INVALID_HANDLE_VALUE)
850            return -1;
851
852        if(!GetConsoleScreenBufferInfo(win32_hout, &csbi))
853            return -1;
854
855        /* Sample code to get the biggest possible window */
856        //size = GetLargestConsoleWindowSize(win32_hout);
857
858        _caca_width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
859        _caca_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
860
861        size.X = _caca_width;
862        size.Y = _caca_height;
863        SetConsoleScreenBufferSize(win32_front, size);
864        SetConsoleScreenBufferSize(win32_back, size);
865
866        SetConsoleMode(win32_front, 0);
867        SetConsoleMode(win32_back, 0);
868
869        GetConsoleCursorInfo(win32_front, &cci);
870        cci.dwSize = 0;
871        cci.bVisible = FALSE;
872        SetConsoleCursorInfo(win32_front, &cci);
873        SetConsoleCursorInfo(win32_back, &cci);
874
875        SetConsoleActiveScreenBuffer(win32_front);
876
877        win32_buffer = malloc(_caca_width * _caca_height * sizeof(CHAR_INFO));
878        if(win32_buffer == NULL)
879            return -1;
880    }
881    else
882#endif
883    {
884        /* Dummy */
885    }
886
887    cache_char = malloc(_caca_width * _caca_height * sizeof(uint8_t));
888    if(cache_char == NULL)
889        return -1;
890
891    cache_attr = malloc(_caca_width * _caca_height * sizeof(uint8_t));
892    if(cache_attr == NULL)
893    {
894        free(cache_char);
895        return -1;
896    }
897
898    memset(cache_char, 0, _caca_width * _caca_height * sizeof(uint8_t));
899    memset(cache_attr, 0, _caca_width * _caca_height * sizeof(uint8_t));
900
901    _caca_empty_line = malloc(_caca_width + 1);
902    memset(_caca_empty_line, ' ', _caca_width);
903    _caca_empty_line[_caca_width] = '\0';
904
905    _caca_scratch_line = malloc(_caca_width + 1);
906
907    _caca_delay = 0;
908    _caca_rendertime = 0;
909
910    return 0;
911}
912
913int _caca_end_graphics(void)
914{
915    free(cache_char);
916    free(cache_attr);
917
918#if defined(USE_SLANG)
919    /* Nothing to do */
920#endif
921#if defined(USE_NCURSES)
922    /* Nothing to do */
923#endif
924#if defined(USE_CONIO)
925    if(_caca_driver == CACA_DRIVER_CONIO)
926    {
927        free(conio_screen);
928    }
929    else
930#endif
931#if defined(USE_X11)
932    if(_caca_driver == CACA_DRIVER_X11)
933    {
934        XSync(x11_dpy, False);
935#if defined(HAVE_X11_XKBLIB_H)
936        if(!x11_detect_autorepeat)
937            XAutoRepeatOn(x11_dpy);
938#endif
939        XFreePixmap(x11_dpy, x11_pixmap);
940        XFreeFont(x11_dpy, x11_font_struct);
941        XFreeGC(x11_dpy, x11_gc);
942        XUnmapWindow(x11_dpy, x11_window);
943        XDestroyWindow(x11_dpy, x11_window);
944        XCloseDisplay(x11_dpy);
945    }
946    else
947#endif
948#if defined(USE_WIN32)
949    if(_caca_driver == CACA_DRIVER_WIN32)
950    {
951        SetConsoleActiveScreenBuffer(win32_hout);
952        CloseHandle(win32_back);
953        CloseHandle(win32_front);
954    }
955    else
956#endif
957    {
958        /* Dummy */
959    }
960
961    free(_caca_empty_line);
962
963    return 0;
964}
965#endif /* _DOXYGEN_SKIP_ME */
966
967/** \brief Set the window title.
968 *
969 *  If libcaca runs in a window, try to change its title. This works with
970 *  the X11 and Win32 drivers.
971 *
972 *  \param title The desired window title.
973 *  \return 0 upon success, a non-zero value if an error occurs.
974 */
975int caca_set_window_title(char const *title)
976{
977#if defined(USE_X11)
978    if(_caca_driver == CACA_DRIVER_X11)
979    {
980        XStoreName(x11_dpy, x11_window, title);
981    }
982    else
983#endif
984#if defined(USE_WIN32)
985    if(_caca_driver == CACA_DRIVER_WIN32)
986    {
987        SetConsoleTitle(title);
988    }
989    else
990#endif
991    {
992        /* Not supported */
993        return -1;
994    }
995
996    return 0;
997}
998
999/** \brief Get the window width.
1000 *
1001 *  If libcaca runs in a window, get the usable window width. This value can
1002 *  be used for aspect ratio calculation. If libcaca does not run in a window
1003 *  or if there is no way to know the font size, assume a 6x10 font is being
1004 *  used. Note that the units are not necessarily pixels.
1005 *
1006 *  \return The window width.
1007 */
1008unsigned int caca_get_window_width(void)
1009{
1010#if defined(USE_X11)
1011    if(_caca_driver == CACA_DRIVER_X11)
1012    {
1013        return _caca_width * x11_font_width;
1014    }
1015    else
1016#endif
1017#if defined(USE_WIN32)
1018    if(_caca_driver == CACA_DRIVER_WIN32)
1019    {
1020        /* FIXME */
1021    }
1022    else
1023#endif
1024    {
1025        /* Dummy */
1026    }
1027
1028    /* Fallback to a 6x10 font */
1029    return _caca_width * 6;
1030}
1031
1032/** \brief Get the window height.
1033 *
1034 *  If libcaca runs in a window, get the usable window height. This value can
1035 *  be used for aspect ratio calculation. If libcaca does not run in a window
1036 *  or if there is no way to know the font size, assume a 6x10 font is being
1037 *  used. Note that the units are not necessarily pixels.
1038 *
1039 *  \return The window height.
1040 */
1041unsigned int caca_get_window_height(void)
1042{
1043#if defined(USE_X11)
1044    if(_caca_driver == CACA_DRIVER_X11)
1045    {
1046        return _caca_height * x11_font_height;
1047    }
1048    else
1049#endif
1050#if defined(USE_WIN32)
1051    if(_caca_driver == CACA_DRIVER_WIN32)
1052    {
1053        /* FIXME */
1054    }
1055    else
1056#endif
1057    {
1058        /* Dummy */
1059    }
1060
1061    /* Fallback to a 6x10 font */
1062    return _caca_height * 10;
1063}
1064
1065/** \brief Set the refresh delay.
1066 *
1067 *  This function sets the refresh delay in microseconds. The refresh delay
1068 *  is used by caca_refresh() to achieve constant framerate. See the
1069 *  caca_refresh() documentation for more details.
1070 *
1071 *  If the argument is zero, constant framerate is disabled. This is the
1072 *  default behaviour.
1073 *
1074 *  \param usec The refresh delay in microseconds.
1075 */
1076void caca_set_delay(unsigned int usec)
1077{
1078    _caca_delay = usec;
1079}
1080
1081/** \brief Get the average rendering time.
1082 *
1083 *  This function returns the average rendering time, which is the average
1084 *  measured time between two caca_refresh() calls, in microseconds. If
1085 *  constant framerate was activated by calling caca_set_delay(), the average
1086 *  rendering time will not be considerably shorter than the requested delay
1087 *  even if the real rendering time was shorter.
1088 *
1089 *  \return The render time in microseconds.
1090 */
1091unsigned int caca_get_rendertime(void)
1092{
1093    return _caca_rendertime;
1094}
1095
1096/** \brief Flush pending changes and redraw the screen.
1097 *
1098 *  This function flushes all graphical operations and prints them to the
1099 *  screen. Nothing will show on the screen until caca_refresh() is
1100 *  called.
1101 *
1102 *  If caca_set_delay() was called with a non-zero value, caca_refresh()
1103 *  will use that value to achieve constant framerate: if two consecutive
1104 *  calls to caca_refresh() are within a time range shorter than the value
1105 *  set with caca_set_delay(), the second call will wait a bit before
1106 *  performing the screen refresh.
1107 */
1108void caca_refresh(void)
1109{
1110#if !defined(_DOXYGEN_SKIP_ME)
1111#define IDLE_USEC 10000
1112#endif
1113    static struct caca_timer timer = CACA_TIMER_INITIALIZER;
1114    static int lastticks = 0;
1115    int ticks = lastticks + _caca_getticks(&timer);
1116
1117#if defined(USE_SLANG)
1118    if(_caca_driver == CACA_DRIVER_SLANG)
1119    {
1120        SLsmg_refresh();
1121    }
1122    else
1123#endif
1124#if defined(USE_NCURSES)
1125    if(_caca_driver == CACA_DRIVER_NCURSES)
1126    {
1127        refresh();
1128    }
1129    else
1130#endif
1131#if defined(USE_CONIO)
1132    if(_caca_driver == CACA_DRIVER_CONIO)
1133    {
1134#   if defined(SCREENUPDATE_IN_PC_H)
1135        ScreenUpdate(conio_screen);
1136#   else
1137        /* FIXME */
1138#   endif
1139    }
1140    else
1141#endif
1142#if defined(USE_X11)
1143    if(_caca_driver == CACA_DRIVER_X11)
1144    {
1145        unsigned int x, y, len;
1146
1147        /* First draw the background colours. Splitting the process in two
1148         * loops like this is actually slightly faster. */
1149        for(y = 0; y < _caca_height; y++)
1150        {
1151            for(x = 0; x < _caca_width; x += len)
1152            {
1153                uint8_t *attr = cache_attr + x + y * _caca_width;
1154
1155                len = 1;
1156                while(x + len < _caca_width
1157                       && (attr[len] >> 4) == (attr[0] >> 4))
1158                    len++;
1159
1160                XSetForeground(x11_dpy, x11_gc, x11_colors[attr[0] >> 4]);
1161                XFillRectangle(x11_dpy, x11_pixmap, x11_gc,
1162                               x * x11_font_width, y * x11_font_height,
1163                               len * x11_font_width, x11_font_height);
1164            }
1165        }
1166
1167        /* Then print the foreground characters */
1168        for(y = 0; y < _caca_height; y++)
1169        {
1170            for(x = 0; x < _caca_width; x += len)
1171            {
1172                uint8_t *attr = cache_attr + x + y * _caca_width;
1173
1174                len = 1;
1175
1176                /* Skip spaces */
1177                if(cache_char[x + y * _caca_width] == ' ')
1178                    continue;
1179
1180                while(x + len < _caca_width
1181                       && (attr[len] & 0xf) == (attr[0] & 0xf))
1182                    len++;
1183
1184                XSetForeground(x11_dpy, x11_gc, x11_colors[attr[0] & 0xf]);
1185                XDrawString(x11_dpy, x11_pixmap, x11_gc, x * x11_font_width,
1186                            (y + 1) * x11_font_height - x11_font_offset,
1187                            cache_char + x + y * _caca_width, len);
1188            }
1189        }
1190
1191        XCopyArea(x11_dpy, x11_pixmap, x11_window, x11_gc, 0, 0,
1192                  _caca_width * x11_font_width, _caca_height * x11_font_height,
1193                  0, 0);
1194        XFlush(x11_dpy);
1195    }
1196    else
1197#endif
1198#if defined(USE_WIN32)
1199    if(_caca_driver == CACA_DRIVER_WIN32)
1200    {
1201        COORD size, pos;
1202        SMALL_RECT rect;
1203        unsigned int i;
1204
1205        /* Render everything to our back buffer */
1206        for(i = 0; i < _caca_width * _caca_height; i++)
1207        {
1208            win32_buffer[i].Char.AsciiChar = cache_char[i];
1209            win32_buffer[i].Attributes = win32_fg_palette[cache_attr[i] & 0xf]
1210                                       | win32_bg_palette[cache_attr[i] >> 4];
1211        }
1212
1213        /* Blit the back buffer to the front buffer */
1214        size.X = _caca_width;
1215        size.Y = _caca_height;
1216        pos.X = pos.Y = 0;
1217        rect.Left = rect.Top = 0;
1218        rect.Right = _caca_width - 1;
1219        rect.Bottom = _caca_height - 1;
1220        WriteConsoleOutput(win32_front, win32_buffer, size, pos, &rect);
1221    }
1222    else
1223#endif
1224    {
1225        /* Dummy */
1226    }
1227
1228    if(_caca_resize)
1229    {
1230        _caca_resize = 0;
1231        caca_handle_resize();
1232    }
1233
1234    /* Wait until _caca_delay + time of last call */
1235    ticks += _caca_getticks(&timer);
1236    for(ticks += _caca_getticks(&timer);
1237        ticks + IDLE_USEC < (int)_caca_delay;
1238        ticks += _caca_getticks(&timer))
1239    {
1240        _caca_sleep(IDLE_USEC);
1241    }
1242
1243    /* Update the sliding mean of the render time */
1244    _caca_rendertime = (7 * _caca_rendertime + ticks) / 8;
1245
1246    lastticks = ticks - _caca_delay;
1247
1248    /* If we drifted too much, it's bad, bad, bad. */
1249    if(lastticks > (int)_caca_delay)
1250        lastticks = 0;
1251}
1252
1253/*
1254 * XXX: following functions are loca
1255 */
1256static void caca_handle_resize(void)
1257{
1258    unsigned int old_width = _caca_width;
1259    unsigned int old_height = _caca_height;
1260
1261#if defined(USE_SLANG)
1262    if(_caca_driver == CACA_DRIVER_SLANG)
1263    {
1264        SLtt_get_screen_size();
1265        _caca_width = SLtt_Screen_Cols;
1266        _caca_height = SLtt_Screen_Rows;
1267
1268        if(_caca_width != old_width || _caca_height != old_height)
1269            SLsmg_reinit_smg();
1270    }
1271    else
1272#endif
1273#if defined(USE_NCURSES)
1274    if(_caca_driver == CACA_DRIVER_NCURSES)
1275    {
1276        struct winsize size;
1277
1278        if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0)
1279        {
1280            _caca_width = size.ws_col;
1281            _caca_height = size.ws_row;
1282#if defined(HAVE_RESIZE_TERM)
1283            resize_term(_caca_height, _caca_width);
1284#else
1285            resizeterm(_caca_height, _caca_width);
1286#endif
1287            wrefresh(curscr);
1288        }
1289    }
1290    else
1291#endif
1292#if defined(USE_CONIO)
1293    if(_caca_driver == CACA_DRIVER_CONIO)
1294    {
1295    }
1296    else
1297#endif
1298#if defined(USE_X11)
1299    if(_caca_driver == CACA_DRIVER_X11)
1300    {
1301        Pixmap new_pixmap;
1302
1303        _caca_width = x11_new_width;
1304        _caca_height = x11_new_height;
1305
1306        new_pixmap = XCreatePixmap(x11_dpy, x11_window,
1307                                   _caca_width * x11_font_width,
1308                                   _caca_height * x11_font_height,
1309                                   DefaultDepth(x11_dpy,
1310                                                DefaultScreen(x11_dpy)));
1311        XCopyArea(x11_dpy, x11_pixmap, new_pixmap, x11_gc, 0, 0,
1312                  old_width * x11_font_width, old_height * x11_font_height,
1313                  0, 0);
1314        XFreePixmap(x11_dpy, x11_pixmap);
1315        x11_pixmap = new_pixmap;
1316    }
1317    else
1318#endif
1319#if defined(USE_WIN32)
1320    if(_caca_driver == CACA_DRIVER_WIN32)
1321    {
1322    }
1323    else
1324#endif
1325    {
1326        /* Dummy */
1327    }
1328
1329    if(_caca_width != old_width || _caca_height != old_height)
1330    {
1331        free(cache_char);
1332        free(cache_attr);
1333
1334        cache_char = malloc(_caca_width * _caca_height * sizeof(uint8_t));
1335        memset(cache_char, 0, _caca_width * _caca_height * sizeof(uint8_t));
1336        cache_attr = malloc(_caca_width * _caca_height * sizeof(uint8_t));
1337        memset(cache_attr, 0, _caca_width * _caca_height * sizeof(uint8_t));
1338    }
1339
1340    if(_caca_width != old_width)
1341    {
1342        free(_caca_empty_line);
1343        _caca_empty_line = malloc(_caca_width + 1);
1344        memset(_caca_empty_line, ' ', _caca_width);
1345        _caca_empty_line[_caca_width] = '\0';
1346
1347        free(_caca_scratch_line);
1348        _caca_scratch_line = malloc(_caca_width + 1);
1349    }
1350}
1351
1352#if defined(USE_SLANG)
1353static void slang_init_palette(void)
1354{
1355    /* See SLang ref., 5.4.4. */
1356    static char *slang_colors[16] =
1357    {
1358        /* Standard colours */
1359        "black",
1360        "blue",
1361        "green",
1362        "cyan",
1363        "red",
1364        "magenta",
1365        "brown",
1366        "lightgray",
1367        /* Bright colours */
1368        "gray",
1369        "brightblue",
1370        "brightgreen",
1371        "brightcyan",
1372        "brightred",
1373        "brightmagenta",
1374        "yellow",
1375        "white",
1376    };
1377
1378#if defined(OPTIMISE_SLANG_PALETTE)
1379    int i;
1380
1381    for(i = 0; i < 16 * 16; i++)
1382        SLtt_set_color(i, NULL, slang_colors[slang_palette[i * 2]],
1383                                slang_colors[slang_palette[i * 2 + 1]]);
1384#else
1385    int fg, bg;
1386
1387    for(bg = 0; bg < 16; bg++)
1388        for(fg = 0; fg < 16; fg++)
1389        {
1390            int i = fg + 16 * bg;
1391            SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]);
1392        }
1393#endif
1394}
1395#endif /* USE_SLANG */
1396
1397#if defined(USE_X11)
1398static int x11_error_handler(Display *dpy, XErrorEvent *event)
1399{
1400    /* Ignore the error */
1401    return 0;
1402}
1403#endif
1404
1405#if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
1406static RETSIGTYPE sigwinch_handler(int sig)
1407{
1408    _caca_resize_event = 1;
1409
1410    signal(SIGWINCH, sigwinch_handler);;
1411}
1412#endif
1413
Note: See TracBrowser for help on using the repository browser.