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

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