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

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