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

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