source: libcaca/trunk/caca/graphics.c @ 536

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