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

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