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

Last change on this file since 524 was 524, checked in by Sam Hocevar, 16 years ago

A new low-level text management library (canvas for ultrafast compositing

of unicode letters) is now separated from the higher level rendering and I/O
(that is, libcaca). This commit totally breaks the API, but once everything
is polished I will think about source-level backward compatibility. Most
drivers are broken, but X11 still sorta works.

The new design is much more object-oriented and allows having several

active renderers at the same time, changing renderers on the fly, and more
important, having no renderer at all (useful for converters, or when you
want to do your own renderer).

And in case you are still wondering, the libcucul acronym has "Unicode"

because I want to support at least a subset of Unicode. There are awesome
glyphs in it, including the ones inherited from Codepage 437 such as
"gray 25%" that are used in DOS and Win32 ANSI art.

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