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

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