source: libcaca/branches/0.9/src/graphics.c @ 3583

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