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

Last change on this file since 463 was 463, checked in by Sam Hocevar, 17 years ago
  • src/graphics.c: + Implemented caca_get_screen().
  • Property svn:keywords set to Id
File size: 39.5 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 463 2005-01-13 22:19:01Z 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#if defined(USE_CONIO) | defined(USE_X11) | defined(USE_WIN32)
437    char *charbuf;
438#endif
439#if defined(USE_X11) | defined(USE_WIN32)
440    char *attrbuf;
441#endif
442    char const *t;
443    unsigned int len;
444
445    if(y < 0 || y >= (int)_caca_height || x >= (int)_caca_width)
446        return;
447
448    len = strlen(s);
449
450    if(x < 0)
451    {
452        if(len < (unsigned int)-x)
453            return;
454        len -= -x;
455        s += -x;
456        x = 0;
457    }
458
459    if(x + len >= _caca_width)
460    {
461        len = _caca_width - x;
462        memcpy(_caca_scratch_line, s, len);
463        _caca_scratch_line[len] = '\0';
464        s = _caca_scratch_line;
465    }
466
467    charbuf = cache_char + x + y * _caca_width;
468    attrbuf = cache_attr + x + y * _caca_width;
469    t = s;
470    while(*t)
471    {
472        *charbuf++ = *t++;
473        *attrbuf++ = (_caca_bgcolor << 4) | _caca_fgcolor;
474    }
475
476    switch(_caca_driver)
477    {
478#if defined(USE_SLANG)
479    case CACA_DRIVER_SLANG:
480        SLsmg_gotorc(y, x);
481#if defined(OPTIMISE_SLANG_PALETTE)
482        if(_caca_fgisbg)
483            SLsmg_write_string(_caca_empty_line + _caca_width - len);
484        else
485#endif
486        {
487            union { char *ch; const char *constch; } u;
488            u.constch = s;
489            SLsmg_write_string(u.ch);
490        }
491        break;
492#endif
493#if defined(USE_NCURSES)
494    case CACA_DRIVER_NCURSES:
495        move(y, x);
496        addstr(s);
497        break;
498#endif
499#if defined(USE_CONIO)
500    case CACA_DRIVER_CONIO:
501        charbuf = conio_screen + 2 * (x + y * _caca_width);
502        while(*s)
503        {
504            *charbuf++ = *s++;
505            *charbuf++ = (_caca_bgcolor << 4) | _caca_fgcolor;
506        }
507        break;
508#endif
509#if defined(USE_X11)
510    case CACA_DRIVER_X11:
511        break;
512#endif
513#if defined(USE_WIN32)
514    case CACA_DRIVER_WIN32:
515        break;
516#endif
517    default:
518        break;
519    }
520}
521
522/** \brief Format a string.
523 *
524 *  This function formats a string at the given coordinates, using the
525 *  default foreground and background values. The coordinates may be outside
526 *  the screen boundaries (eg. a negative Y coordinate) and the string will
527 *  be cropped accordingly if it is too long. The syntax of the format
528 *  string is the same as for the C printf() function.
529 *
530 *  \param x X coordinate.
531 *  \param y Y coordinate.
532 *  \param format The format string to print.
533 *  \param ... Arguments to the format string.
534 */
535void caca_printf(int x, int y, char const *format, ...)
536{
537    char tmp[BUFSIZ];
538    char *buf = tmp;
539    va_list args;
540
541    if(y < 0 || y >= (int)_caca_height || x >= (int)_caca_width)
542        return;
543
544    if(_caca_width - x + 1 > BUFSIZ)
545        buf = malloc(_caca_width - x + 1);
546
547    va_start(args, format);
548#if defined(HAVE_VSNPRINTF)
549    vsnprintf(buf, _caca_width - x + 1, format, args);
550#else
551    vsprintf(buf, format, args);
552#endif
553    buf[_caca_width - x] = '\0';
554    va_end(args);
555
556    caca_putstr(x, y, buf);
557
558    if(buf != tmp)
559        free(buf);
560}
561
562/** \brief Get the screen.
563 *
564 *  This function fills a byte array with the character values.
565 */
566void caca_get_screen(char *buffer)
567{
568    unsigned int x, y;
569
570    for(y = 0; y < _caca_height; y++)
571    {
572        for(x = 0; x < _caca_width; x++)
573        {
574            *buffer++ = cache_attr[x + y * _caca_width];
575            *buffer++ = cache_char[x + y * _caca_width];
576        }
577    }
578}
579
580/** \brief Clear the screen.
581 *
582 *  This function clears the screen using a black background.
583 */
584void caca_clear(void)
585{
586    enum caca_color oldfg = caca_get_fg_color();
587    enum caca_color oldbg = caca_get_bg_color();
588    int y = _caca_height;
589
590    caca_set_color(CACA_COLOR_LIGHTGRAY, CACA_COLOR_BLACK);
591
592    /* We could use SLsmg_cls() etc., but drawing empty lines is much faster */
593    while(y--)
594        caca_putstr(0, y, _caca_empty_line);
595
596    caca_set_color(oldfg, oldbg);
597}
598
599#if !defined(_DOXYGEN_SKIP_ME)
600int _caca_init_graphics(void)
601{
602#if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
603    signal(SIGWINCH, sigwinch_handler);
604#endif
605
606#if defined(USE_SLANG)
607    if(_caca_driver == CACA_DRIVER_SLANG)
608    {
609        slang_init_palette();
610
611        /* Disable alt charset support so that we get a chance to have all
612         * 256 colour pairs */
613        SLtt_Has_Alt_Charset = 0;
614
615        _caca_width = SLtt_Screen_Cols;
616        _caca_height = SLtt_Screen_Rows;
617    }
618    else
619#endif
620#if defined(USE_NCURSES)
621    if(_caca_driver == CACA_DRIVER_NCURSES)
622    {
623        static int curses_colors[] =
624        {
625            /* Standard curses colours */
626            COLOR_BLACK,
627            COLOR_BLUE,
628            COLOR_GREEN,
629            COLOR_CYAN,
630            COLOR_RED,
631            COLOR_MAGENTA,
632            COLOR_YELLOW,
633            COLOR_WHITE,
634            /* Extra values for xterm-16color */
635            COLOR_BLACK + 8,
636            COLOR_BLUE + 8,
637            COLOR_GREEN + 8,
638            COLOR_CYAN + 8,
639            COLOR_RED + 8,
640            COLOR_MAGENTA + 8,
641            COLOR_YELLOW + 8,
642            COLOR_WHITE + 8
643        };
644
645        int fg, bg, max;
646
647        /* Activate colour */
648        start_color();
649
650        /* If COLORS == 16, it means the terminal supports full bright colours
651         * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
652         * we can build 16*16 colour pairs.
653         * If COLORS == 8, it means the terminal does not know about bright
654         * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
655         * and \e[5m). We can only build 8*8 colour pairs. */
656        max = COLORS >= 16 ? 16 : 8;
657
658        for(bg = 0; bg < max; bg++)
659            for(fg = 0; fg < max; fg++)
660            {
661                /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
662                 * is light gray on black, since some terminals don't like
663                 * this colour pair to be redefined. */
664                int col = ((max + 7 - fg) % max) + max * bg;
665                init_pair(col, curses_colors[fg], curses_colors[bg]);
666                ncurses_attr[fg + 16 * bg] = COLOR_PAIR(col);
667
668                if(max == 8)
669                {
670                    /* Bright fg on simple bg */
671                    ncurses_attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
672                    /* Simple fg on bright bg */
673                    ncurses_attr[fg + 16 * (bg + 8)] = A_BLINK
674                                                        | COLOR_PAIR(col);
675                    /* Bright fg on bright bg */
676                    ncurses_attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
677                                                            | COLOR_PAIR(col);
678                }
679            }
680
681        _caca_width = COLS;
682        _caca_height = LINES;
683    }
684    else
685#endif
686#if defined(USE_CONIO)
687    if(_caca_driver == CACA_DRIVER_CONIO)
688    {
689        gettextinfo(&conio_ti);
690        conio_screen = malloc(2 * conio_ti.screenwidth
691                                 * conio_ti.screenheight * sizeof(char));
692        if(conio_screen == NULL)
693            return -1;
694#   if defined(SCREENUPDATE_IN_PC_H)
695        ScreenRetrieve(conio_screen);
696#   else
697        /* FIXME */
698#   endif
699        _caca_width = conio_ti.screenwidth;
700        _caca_height = conio_ti.screenheight;
701    }
702    else
703#endif
704#if defined(USE_X11)
705    if(_caca_driver == CACA_DRIVER_X11)
706    {
707        static int x11_palette[] =
708        {
709            /* Standard curses colours */
710            0x0,    0x0,    0x0,
711            0x0,    0x0,    0x8000,
712            0x0,    0x8000, 0x0,
713            0x0,    0x8000, 0x8000,
714            0x8000, 0x0,    0x0,
715            0x8000, 0x0,    0x8000,
716            0x8000, 0x8000, 0x0,
717            0x8000, 0x8000, 0x8000,
718            /* Extra values for xterm-16color */
719            0x4000, 0x4000, 0x4000,
720            0x4000, 0x4000, 0xffff,
721            0x4000, 0xffff, 0x4000,
722            0x4000, 0xffff, 0xffff,
723            0xffff, 0x4000, 0x4000,
724            0xffff, 0x4000, 0xffff,
725            0xffff, 0xffff, 0x4000,
726            0xffff, 0xffff, 0xffff,
727        };
728
729        Colormap colormap;
730        XSetWindowAttributes x11_winattr;
731        int (*old_error_handler)(Display *, XErrorEvent *);
732        char const *font_name = "8x13bold";
733        int i;
734
735        if(getenv("CACA_GEOMETRY") && *(getenv("CACA_GEOMETRY")))
736            sscanf(getenv("CACA_GEOMETRY"),
737                   "%ux%u", &_caca_width, &_caca_height);
738
739        if(!_caca_width)
740            _caca_width = 80;
741        if(!_caca_height)
742            _caca_height = 32;
743
744        x11_dpy = XOpenDisplay(NULL);
745        if(x11_dpy == NULL)
746            return -1;
747
748        if(getenv("CACA_FONT") && *(getenv("CACA_FONT")))
749            font_name = getenv("CACA_FONT");
750
751        /* Ignore font errors */
752        old_error_handler = XSetErrorHandler(x11_error_handler);
753
754        x11_font = XLoadFont(x11_dpy, font_name);
755        if(!x11_font)
756        {
757            XCloseDisplay(x11_dpy);
758            return -1;
759        }
760
761        x11_font_struct = XQueryFont(x11_dpy, x11_font);
762        if(!x11_font_struct)
763        {
764            XUnloadFont(x11_dpy, x11_font);
765            XCloseDisplay(x11_dpy);
766            return -1;
767        }
768
769        /* Reset the default X11 error handler */
770        XSetErrorHandler(old_error_handler);
771
772        x11_font_width = x11_font_struct->max_bounds.width;
773        x11_font_height = x11_font_struct->max_bounds.ascent
774                             + x11_font_struct->max_bounds.descent;
775        x11_font_offset = x11_font_struct->max_bounds.descent;
776
777        colormap = DefaultColormap(x11_dpy, DefaultScreen(x11_dpy));
778        for(i = 0; i < 16; i++)
779        {
780            XColor color;
781            color.red = x11_palette[i * 3];
782            color.green = x11_palette[i * 3 + 1];
783            color.blue = x11_palette[i * 3 + 2];
784            XAllocColor(x11_dpy, colormap, &color);
785            x11_colors[i] = color.pixel;
786        }
787
788        x11_winattr.backing_store = Always;
789        x11_winattr.background_pixel = x11_colors[0];
790        x11_winattr.event_mask = ExposureMask | StructureNotifyMask;
791
792        x11_window = XCreateWindow(x11_dpy, DefaultRootWindow(x11_dpy), 0, 0,
793                                   _caca_width * x11_font_width,
794                                   _caca_height * x11_font_height,
795                                   0, 0, InputOutput, 0,
796                                   CWBackingStore | CWBackPixel | CWEventMask,
797                                   &x11_winattr);
798
799        XStoreName(x11_dpy, x11_window, "caca for X");
800
801        XSelectInput(x11_dpy, x11_window, StructureNotifyMask);
802        XMapWindow(x11_dpy, x11_window);
803
804        x11_gc = XCreateGC(x11_dpy, x11_window, 0, NULL);
805        XSetForeground(x11_dpy, x11_gc, x11_colors[15]);
806        XSetFont(x11_dpy, x11_gc, x11_font);
807
808        for(;;)
809        {
810            XEvent event;
811            XNextEvent(x11_dpy, &event);
812            if (event.type == MapNotify)
813                break;
814        }
815
816        /* Disable autorepeat */
817#if defined(HAVE_X11_XKBLIB_H)
818        XkbSetDetectableAutoRepeat(x11_dpy, True, &x11_detect_autorepeat);
819        if(!x11_detect_autorepeat)
820            XAutoRepeatOff(x11_dpy);
821#endif
822
823        XSelectInput(x11_dpy, x11_window, x11_event_mask);
824
825        XSync(x11_dpy, False);
826
827        x11_pixmap = XCreatePixmap(x11_dpy, x11_window,
828                                   _caca_width * x11_font_width,
829                                   _caca_height * x11_font_height,
830                                   DefaultDepth(x11_dpy,
831                                                DefaultScreen(x11_dpy)));
832
833        x11_new_width = x11_new_height = 0;
834    }
835    else
836#endif
837#if defined(USE_WIN32)
838    if(_caca_driver == CACA_DRIVER_WIN32)
839    {
840        CONSOLE_CURSOR_INFO cci;
841        CONSOLE_SCREEN_BUFFER_INFO csbi;
842        COORD size;
843
844        win32_front = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
845                                                0, NULL,
846                                                CONSOLE_TEXTMODE_BUFFER, NULL);
847        if(!win32_front || win32_front == INVALID_HANDLE_VALUE)
848            return -1;
849
850        win32_back = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
851                                               0, NULL,
852                                               CONSOLE_TEXTMODE_BUFFER, NULL);
853        if(!win32_back || win32_back == INVALID_HANDLE_VALUE)
854            return -1;
855
856        if(!GetConsoleScreenBufferInfo(win32_hout, &csbi))
857            return -1;
858
859        /* Sample code to get the biggest possible window */
860        //size = GetLargestConsoleWindowSize(win32_hout);
861
862        _caca_width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
863        _caca_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
864
865        size.X = _caca_width;
866        size.Y = _caca_height;
867        SetConsoleScreenBufferSize(win32_front, size);
868        SetConsoleScreenBufferSize(win32_back, size);
869
870        SetConsoleMode(win32_front, 0);
871        SetConsoleMode(win32_back, 0);
872
873        GetConsoleCursorInfo(win32_front, &cci);
874        cci.dwSize = 0;
875        cci.bVisible = FALSE;
876        SetConsoleCursorInfo(win32_front, &cci);
877        SetConsoleCursorInfo(win32_back, &cci);
878
879        SetConsoleActiveScreenBuffer(win32_front);
880
881        win32_buffer = malloc(_caca_width * _caca_height * sizeof(CHAR_INFO));
882        if(win32_buffer == NULL)
883            return -1;
884    }
885    else
886#endif
887    {
888        /* Dummy */
889    }
890
891    cache_char = malloc(_caca_width * _caca_height * sizeof(uint8_t));
892    if(cache_char == NULL)
893        return -1;
894
895    cache_attr = malloc(_caca_width * _caca_height * sizeof(uint8_t));
896    if(cache_attr == NULL)
897    {
898        free(cache_char);
899        return -1;
900    }
901
902    memset(cache_char, 0, _caca_width * _caca_height * sizeof(uint8_t));
903    memset(cache_attr, 0, _caca_width * _caca_height * sizeof(uint8_t));
904
905    _caca_empty_line = malloc(_caca_width + 1);
906    memset(_caca_empty_line, ' ', _caca_width);
907    _caca_empty_line[_caca_width] = '\0';
908
909    _caca_scratch_line = malloc(_caca_width + 1);
910
911    _caca_delay = 0;
912    _caca_rendertime = 0;
913
914    return 0;
915}
916
917int _caca_end_graphics(void)
918{
919    free(cache_char);
920    free(cache_attr);
921
922#if defined(USE_SLANG)
923    /* Nothing to do */
924#endif
925#if defined(USE_NCURSES)
926    /* Nothing to do */
927#endif
928#if defined(USE_CONIO)
929    if(_caca_driver == CACA_DRIVER_CONIO)
930    {
931        free(conio_screen);
932    }
933    else
934#endif
935#if defined(USE_X11)
936    if(_caca_driver == CACA_DRIVER_X11)
937    {
938        XSync(x11_dpy, False);
939#if defined(HAVE_X11_XKBLIB_H)
940        if(!x11_detect_autorepeat)
941            XAutoRepeatOn(x11_dpy);
942#endif
943        XFreePixmap(x11_dpy, x11_pixmap);
944        XFreeFont(x11_dpy, x11_font_struct);
945        XFreeGC(x11_dpy, x11_gc);
946        XUnmapWindow(x11_dpy, x11_window);
947        XDestroyWindow(x11_dpy, x11_window);
948        XCloseDisplay(x11_dpy);
949    }
950    else
951#endif
952#if defined(USE_WIN32)
953    if(_caca_driver == CACA_DRIVER_WIN32)
954    {
955        SetConsoleActiveScreenBuffer(win32_hout);
956        CloseHandle(win32_back);
957        CloseHandle(win32_front);
958    }
959    else
960#endif
961    {
962        /* Dummy */
963    }
964
965    free(_caca_empty_line);
966
967    return 0;
968}
969#endif /* _DOXYGEN_SKIP_ME */
970
971/** \brief Set the window title.
972 *
973 *  If libcaca runs in a window, try to change its title. This works with
974 *  the X11 and Win32 drivers.
975 *
976 *  \param title The desired window title.
977 *  \return 0 upon success, a non-zero value if an error occurs.
978 */
979int caca_set_window_title(char const *title)
980{
981#if defined(USE_X11)
982    if(_caca_driver == CACA_DRIVER_X11)
983    {
984        XStoreName(x11_dpy, x11_window, title);
985    }
986    else
987#endif
988#if defined(USE_WIN32)
989    if(_caca_driver == CACA_DRIVER_WIN32)
990    {
991        SetConsoleTitle(title);
992    }
993    else
994#endif
995    {
996        /* Not supported */
997        return -1;
998    }
999
1000    return 0;
1001}
1002
1003/** \brief Get the window width.
1004 *
1005 *  If libcaca runs in a window, get the usable window width. This value can
1006 *  be used for aspect ratio calculation. If libcaca does not run in a window
1007 *  or if there is no way to know the font size, assume a 6x10 font is being
1008 *  used. Note that the units are not necessarily pixels.
1009 *
1010 *  \return The window width.
1011 */
1012unsigned int caca_get_window_width(void)
1013{
1014#if defined(USE_X11)
1015    if(_caca_driver == CACA_DRIVER_X11)
1016    {
1017        return _caca_width * x11_font_width;
1018    }
1019    else
1020#endif
1021#if defined(USE_WIN32)
1022    if(_caca_driver == CACA_DRIVER_WIN32)
1023    {
1024        /* FIXME */
1025    }
1026    else
1027#endif
1028    {
1029        /* Dummy */
1030    }
1031
1032    /* Fallback to a 6x10 font */
1033    return _caca_width * 6;
1034}
1035
1036/** \brief Get the window height.
1037 *
1038 *  If libcaca runs in a window, get the usable window height. This value can
1039 *  be used for aspect ratio calculation. If libcaca does not run in a window
1040 *  or if there is no way to know the font size, assume a 6x10 font is being
1041 *  used. Note that the units are not necessarily pixels.
1042 *
1043 *  \return The window height.
1044 */
1045unsigned int caca_get_window_height(void)
1046{
1047#if defined(USE_X11)
1048    if(_caca_driver == CACA_DRIVER_X11)
1049    {
1050        return _caca_height * x11_font_height;
1051    }
1052    else
1053#endif
1054#if defined(USE_WIN32)
1055    if(_caca_driver == CACA_DRIVER_WIN32)
1056    {
1057        /* FIXME */
1058    }
1059    else
1060#endif
1061    {
1062        /* Dummy */
1063    }
1064
1065    /* Fallback to a 6x10 font */
1066    return _caca_height * 10;
1067}
1068
1069/** \brief Set the refresh delay.
1070 *
1071 *  This function sets the refresh delay in microseconds. The refresh delay
1072 *  is used by caca_refresh() to achieve constant framerate. See the
1073 *  caca_refresh() documentation for more details.
1074 *
1075 *  If the argument is zero, constant framerate is disabled. This is the
1076 *  default behaviour.
1077 *
1078 *  \param usec The refresh delay in microseconds.
1079 */
1080void caca_set_delay(unsigned int usec)
1081{
1082    _caca_delay = usec;
1083}
1084
1085/** \brief Get the average rendering time.
1086 *
1087 *  This function returns the average rendering time, which is the average
1088 *  measured time between two caca_refresh() calls, in microseconds. If
1089 *  constant framerate was activated by calling caca_set_delay(), the average
1090 *  rendering time will not be considerably shorter than the requested delay
1091 *  even if the real rendering time was shorter.
1092 *
1093 *  \return The render time in microseconds.
1094 */
1095unsigned int caca_get_rendertime(void)
1096{
1097    return _caca_rendertime;
1098}
1099
1100/** \brief Flush pending changes and redraw the screen.
1101 *
1102 *  This function flushes all graphical operations and prints them to the
1103 *  screen. Nothing will show on the screen until caca_refresh() is
1104 *  called.
1105 *
1106 *  If caca_set_delay() was called with a non-zero value, caca_refresh()
1107 *  will use that value to achieve constant framerate: if two consecutive
1108 *  calls to caca_refresh() are within a time range shorter than the value
1109 *  set with caca_set_delay(), the second call will wait a bit before
1110 *  performing the screen refresh.
1111 */
1112void caca_refresh(void)
1113{
1114#if !defined(_DOXYGEN_SKIP_ME)
1115#define IDLE_USEC 10000
1116#endif
1117    static struct caca_timer timer = CACA_TIMER_INITIALIZER;
1118    static int lastticks = 0;
1119    int ticks = lastticks + _caca_getticks(&timer);
1120
1121#if defined(USE_SLANG)
1122    if(_caca_driver == CACA_DRIVER_SLANG)
1123    {
1124        SLsmg_refresh();
1125    }
1126    else
1127#endif
1128#if defined(USE_NCURSES)
1129    if(_caca_driver == CACA_DRIVER_NCURSES)
1130    {
1131        refresh();
1132    }
1133    else
1134#endif
1135#if defined(USE_CONIO)
1136    if(_caca_driver == CACA_DRIVER_CONIO)
1137    {
1138#   if defined(SCREENUPDATE_IN_PC_H)
1139        ScreenUpdate(conio_screen);
1140#   else
1141        /* FIXME */
1142#   endif
1143    }
1144    else
1145#endif
1146#if defined(USE_X11)
1147    if(_caca_driver == CACA_DRIVER_X11)
1148    {
1149        unsigned int x, y, len;
1150
1151        /* First draw the background colours. Splitting the process in two
1152         * loops like this is actually slightly faster. */
1153        for(y = 0; y < _caca_height; y++)
1154        {
1155            for(x = 0; x < _caca_width; x += len)
1156            {
1157                uint8_t *attr = cache_attr + x + y * _caca_width;
1158
1159                len = 1;
1160                while(x + len < _caca_width
1161                       && (attr[len] >> 4) == (attr[0] >> 4))
1162                    len++;
1163
1164                XSetForeground(x11_dpy, x11_gc, x11_colors[attr[0] >> 4]);
1165                XFillRectangle(x11_dpy, x11_pixmap, x11_gc,
1166                               x * x11_font_width, y * x11_font_height,
1167                               len * x11_font_width, x11_font_height);
1168            }
1169        }
1170
1171        /* Then print the foreground characters */
1172        for(y = 0; y < _caca_height; y++)
1173        {
1174            for(x = 0; x < _caca_width; x += len)
1175            {
1176                uint8_t *attr = cache_attr + x + y * _caca_width;
1177
1178                len = 1;
1179
1180                /* Skip spaces */
1181                if(cache_char[x + y * _caca_width] == ' ')
1182                    continue;
1183
1184                while(x + len < _caca_width
1185                       && (attr[len] & 0xf) == (attr[0] & 0xf))
1186                    len++;
1187
1188                XSetForeground(x11_dpy, x11_gc, x11_colors[attr[0] & 0xf]);
1189                XDrawString(x11_dpy, x11_pixmap, x11_gc, x * x11_font_width,
1190                            (y + 1) * x11_font_height - x11_font_offset,
1191                            cache_char + x + y * _caca_width, len);
1192            }
1193        }
1194
1195        XCopyArea(x11_dpy, x11_pixmap, x11_window, x11_gc, 0, 0,
1196                  _caca_width * x11_font_width, _caca_height * x11_font_height,
1197                  0, 0);
1198        XFlush(x11_dpy);
1199    }
1200    else
1201#endif
1202#if defined(USE_WIN32)
1203    if(_caca_driver == CACA_DRIVER_WIN32)
1204    {
1205        COORD size, pos;
1206        SMALL_RECT rect;
1207        unsigned int i;
1208
1209        /* Render everything to our back buffer */
1210        for(i = 0; i < _caca_width * _caca_height; i++)
1211        {
1212            win32_buffer[i].Char.AsciiChar = cache_char[i];
1213            win32_buffer[i].Attributes = win32_fg_palette[cache_attr[i] & 0xf]
1214                                       | win32_bg_palette[cache_attr[i] >> 4];
1215        }
1216
1217        /* Blit the back buffer to the front buffer */
1218        size.X = _caca_width;
1219        size.Y = _caca_height;
1220        pos.X = pos.Y = 0;
1221        rect.Left = rect.Top = 0;
1222        rect.Right = _caca_width - 1;
1223        rect.Bottom = _caca_height - 1;
1224        WriteConsoleOutput(win32_front, win32_buffer, size, pos, &rect);
1225    }
1226    else
1227#endif
1228    {
1229        /* Dummy */
1230    }
1231
1232    if(_caca_resize)
1233    {
1234        _caca_resize = 0;
1235        caca_handle_resize();
1236    }
1237
1238    /* Wait until _caca_delay + time of last call */
1239    ticks += _caca_getticks(&timer);
1240    for(ticks += _caca_getticks(&timer);
1241        ticks + IDLE_USEC < (int)_caca_delay;
1242        ticks += _caca_getticks(&timer))
1243    {
1244        _caca_sleep(IDLE_USEC);
1245    }
1246
1247    /* Update the sliding mean of the render time */
1248    _caca_rendertime = (7 * _caca_rendertime + ticks) / 8;
1249
1250    lastticks = ticks - _caca_delay;
1251
1252    /* If we drifted too much, it's bad, bad, bad. */
1253    if(lastticks > (int)_caca_delay)
1254        lastticks = 0;
1255}
1256
1257/*
1258 * XXX: following functions are loca
1259 */
1260static void caca_handle_resize(void)
1261{
1262    unsigned int old_width = _caca_width;
1263    unsigned int old_height = _caca_height;
1264
1265#if defined(USE_SLANG)
1266    if(_caca_driver == CACA_DRIVER_SLANG)
1267    {
1268        SLtt_get_screen_size();
1269        _caca_width = SLtt_Screen_Cols;
1270        _caca_height = SLtt_Screen_Rows;
1271
1272        if(_caca_width != old_width || _caca_height != old_height)
1273            SLsmg_reinit_smg();
1274    }
1275    else
1276#endif
1277#if defined(USE_NCURSES)
1278    if(_caca_driver == CACA_DRIVER_NCURSES)
1279    {
1280        struct winsize size;
1281
1282        if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0)
1283        {
1284            _caca_width = size.ws_col;
1285            _caca_height = size.ws_row;
1286#if defined(HAVE_RESIZE_TERM)
1287            resize_term(_caca_height, _caca_width);
1288#else
1289            resizeterm(_caca_height, _caca_width);
1290#endif
1291            wrefresh(curscr);
1292        }
1293    }
1294    else
1295#endif
1296#if defined(USE_CONIO)
1297    if(_caca_driver == CACA_DRIVER_CONIO)
1298    {
1299    }
1300    else
1301#endif
1302#if defined(USE_X11)
1303    if(_caca_driver == CACA_DRIVER_X11)
1304    {
1305        Pixmap new_pixmap;
1306
1307        _caca_width = x11_new_width;
1308        _caca_height = x11_new_height;
1309
1310        new_pixmap = XCreatePixmap(x11_dpy, x11_window,
1311                                   _caca_width * x11_font_width,
1312                                   _caca_height * x11_font_height,
1313                                   DefaultDepth(x11_dpy,
1314                                                DefaultScreen(x11_dpy)));
1315        XCopyArea(x11_dpy, x11_pixmap, new_pixmap, x11_gc, 0, 0,
1316                  old_width * x11_font_width, old_height * x11_font_height,
1317                  0, 0);
1318        XFreePixmap(x11_dpy, x11_pixmap);
1319        x11_pixmap = new_pixmap;
1320    }
1321    else
1322#endif
1323#if defined(USE_WIN32)
1324    if(_caca_driver == CACA_DRIVER_WIN32)
1325    {
1326    }
1327    else
1328#endif
1329    {
1330        /* Dummy */
1331    }
1332
1333    if(_caca_width != old_width || _caca_height != old_height)
1334    {
1335        free(cache_char);
1336        free(cache_attr);
1337
1338        cache_char = malloc(_caca_width * _caca_height * sizeof(uint8_t));
1339        memset(cache_char, 0, _caca_width * _caca_height * sizeof(uint8_t));
1340        cache_attr = malloc(_caca_width * _caca_height * sizeof(uint8_t));
1341        memset(cache_attr, 0, _caca_width * _caca_height * sizeof(uint8_t));
1342    }
1343
1344    if(_caca_width != old_width)
1345    {
1346        free(_caca_empty_line);
1347        _caca_empty_line = malloc(_caca_width + 1);
1348        memset(_caca_empty_line, ' ', _caca_width);
1349        _caca_empty_line[_caca_width] = '\0';
1350
1351        free(_caca_scratch_line);
1352        _caca_scratch_line = malloc(_caca_width + 1);
1353    }
1354}
1355
1356#if defined(USE_SLANG)
1357static void slang_init_palette(void)
1358{
1359    /* See SLang ref., 5.4.4. */
1360    static char *slang_colors[16] =
1361    {
1362        /* Standard colours */
1363        "black",
1364        "blue",
1365        "green",
1366        "cyan",
1367        "red",
1368        "magenta",
1369        "brown",
1370        "lightgray",
1371        /* Bright colours */
1372        "gray",
1373        "brightblue",
1374        "brightgreen",
1375        "brightcyan",
1376        "brightred",
1377        "brightmagenta",
1378        "yellow",
1379        "white",
1380    };
1381
1382#if defined(OPTIMISE_SLANG_PALETTE)
1383    int i;
1384
1385    for(i = 0; i < 16 * 16; i++)
1386        SLtt_set_color(i, NULL, slang_colors[slang_palette[i * 2]],
1387                                slang_colors[slang_palette[i * 2 + 1]]);
1388#else
1389    int fg, bg;
1390
1391    for(bg = 0; bg < 16; bg++)
1392        for(fg = 0; fg < 16; fg++)
1393        {
1394            int i = fg + 16 * bg;
1395            SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]);
1396        }
1397#endif
1398}
1399#endif /* USE_SLANG */
1400
1401#if defined(USE_X11)
1402static int x11_error_handler(Display *dpy, XErrorEvent *event)
1403{
1404    /* Ignore the error */
1405    return 0;
1406}
1407#endif
1408
1409#if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
1410static RETSIGTYPE sigwinch_handler(int sig)
1411{
1412    _caca_resize_event = 1;
1413
1414    signal(SIGWINCH, sigwinch_handler);;
1415}
1416#endif
1417
Note: See TracBrowser for help on using the repository browser.