source: libcaca/trunk/caca/driver_ncurses.c @ 539

Last change on this file since 539 was 539, checked in by Sam Hocevar, 14 years ago
  • Split caca/graphics.c into driver-specific files. Resize is currently broken, and event handling is not yet in the driver-specific files, but I will of course fix that later.
  • Property svn:keywords set to Id
File size: 6.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: driver_ncurses.c 539 2006-03-06 23:01:59Z 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(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME)
23#   include <inttypes.h>
24#else
25typedef unsigned int uint32_t;
26typedef unsigned char uint8_t;
27#endif
28
29#if defined(USE_NCURSES)
30
31#if defined(HAVE_NCURSES_H)
32#   include <ncurses.h>
33#else
34#   include <curses.h>
35#endif
36
37#include <stdio.h> /* BUFSIZ */
38#include <string.h>
39#include <stdlib.h>
40#if defined(HAVE_UNISTD_H)
41#   include <unistd.h>
42#endif
43#include <stdarg.h>
44
45#if defined(HAVE_SIGNAL_H)
46#   include <signal.h>
47#endif
48#if defined(HAVE_SYS_IOCTL_H)
49#   include <sys/ioctl.h>
50#endif
51
52#include "caca.h"
53#include "caca_internals.h"
54#include "cucul.h"
55#include "cucul_internals.h"
56
57int ncurses_init_graphics(caca_t *);
58int ncurses_end_graphics(caca_t *);
59int ncurses_set_window_title(caca_t *, char const *);
60unsigned int ncurses_get_window_width(caca_t *);
61unsigned int ncurses_get_window_height(caca_t *);
62void ncurses_display(caca_t *);
63void ncurses_handle_resize(caca_t *);
64
65/*
66 * Local functions
67 */
68#if defined(HAVE_SIGNAL)
69static RETSIGTYPE sigwinch_handler(int);
70static caca_t *sigwinch_kk; /* FIXME: we ought to get rid of this */
71#endif
72
73int ncurses_init_graphics(caca_t *kk)
74{
75    static int curses_colors[] =
76    {
77        /* Standard curses colours */
78        COLOR_BLACK,
79        COLOR_BLUE,
80        COLOR_GREEN,
81        COLOR_CYAN,
82        COLOR_RED,
83        COLOR_MAGENTA,
84        COLOR_YELLOW,
85        COLOR_WHITE,
86        /* Extra values for xterm-16color */
87        COLOR_BLACK + 8,
88        COLOR_BLUE + 8,
89        COLOR_GREEN + 8,
90        COLOR_CYAN + 8,
91        COLOR_RED + 8,
92        COLOR_MAGENTA + 8,
93        COLOR_YELLOW + 8,
94        COLOR_WHITE + 8
95    };
96
97    mmask_t newmask;
98    int fg, bg, max;
99
100#if defined(HAVE_SIGNAL)
101    sigwinch_kk = kk;
102    signal(SIGWINCH, sigwinch_handler);
103#endif
104
105    initscr();
106    keypad(stdscr, TRUE);
107    nonl();
108    raw();
109    noecho();
110    nodelay(stdscr, TRUE);
111    curs_set(0);
112
113    /* Activate mouse */
114    newmask = REPORT_MOUSE_POSITION | ALL_MOUSE_EVENTS;
115    mousemask(newmask, &kk->ncurses.oldmask);
116    mouseinterval(-1); /* No click emulation */
117
118    /* Set the escape delay to a ridiculously low value */
119    ESCDELAY = 10;
120
121    /* Activate colour */
122    start_color();
123
124    /* If COLORS == 16, it means the terminal supports full bright colours
125     * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
126     * we can build 16*16 colour pairs.
127     * If COLORS == 8, it means the terminal does not know about bright
128     * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
129     * and \e[5m). We can only build 8*8 colour pairs. */
130    max = COLORS >= 16 ? 16 : 8;
131
132    for(bg = 0; bg < max; bg++)
133        for(fg = 0; fg < max; fg++)
134        {
135            /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
136             * is light gray on black. Some terminals don't like this
137             * colour pair to be redefined. */
138            int col = ((max + 7 - fg) % max) + max * bg;
139            init_pair(col, curses_colors[fg], curses_colors[bg]);
140            kk->ncurses.attr[fg + 16 * bg] = COLOR_PAIR(col);
141
142            if(max == 8)
143            {
144                /* Bright fg on simple bg */
145                kk->ncurses.attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
146                /* Simple fg on bright bg */
147                kk->ncurses.attr[fg + 16 * (bg + 8)] = A_BLINK
148                                                    | COLOR_PAIR(col);
149                /* Bright fg on bright bg */
150                kk->ncurses.attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
151                                                        | COLOR_PAIR(col);
152            }
153        }
154
155    cucul_set_size(kk->qq, COLS, LINES);
156
157    return 0;
158}
159
160int ncurses_end_graphics(caca_t *kk)
161{
162    mousemask(kk->ncurses.oldmask, NULL);
163    curs_set(1);
164    noraw();
165    endwin();
166
167    return 0;
168}
169
170int ncurses_set_window_title(caca_t *kk, char const *title)
171{
172    return 0;
173}
174
175unsigned int ncurses_get_window_width(caca_t *kk)
176{
177    /* Fallback to a 6x10 font */
178    return kk->qq->width * 6;
179}
180
181unsigned int ncurses_get_window_height(caca_t *kk)
182{
183    /* Fallback to a 6x10 font */
184    return kk->qq->height * 10;
185}
186
187void ncurses_display(caca_t *kk)
188{
189    int x, y;
190    uint8_t *attr = kk->qq->attr;
191    uint32_t *chars = kk->qq->chars;
192    for(y = 0; y < (int)kk->qq->height; y++)
193    {
194        move(y, 0);
195        for(x = kk->qq->width; x--; )
196        {
197            attrset(kk->ncurses.attr[*attr++]);
198            addch(*chars++ & 0x7f);
199        }
200    }
201    refresh();
202}
203
204void ncurses_handle_resize(caca_t *kk)
205{
206    unsigned int new_width, new_height;
207    struct winsize size;
208
209    new_width = kk->qq->width;
210    new_height = kk->qq->height;
211
212    if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0)
213    {
214        new_width = size.ws_col;
215        new_height = size.ws_row;
216#if defined(HAVE_RESIZE_TERM)
217        resize_term(new_height, new_width);
218#else
219        resizeterm(new_height, new_width);
220#endif
221        wrefresh(curscr);
222    }
223}
224
225/*
226 * XXX: following functions are local
227 */
228
229#if defined(HAVE_SIGNAL)
230static RETSIGTYPE sigwinch_handler(int sig)
231{
232    sigwinch_kk->resize_event = 1;
233
234    signal(SIGWINCH, sigwinch_handler);;
235}
236#endif
237
238/*
239 * Driver initialisation
240 */
241
242void ncurses_init_driver(caca_t *kk)
243{
244    kk->driver.driver = CACA_DRIVER_NCURSES;
245
246    kk->driver.init_graphics = ncurses_init_graphics;
247    kk->driver.end_graphics = ncurses_end_graphics;
248    kk->driver.set_window_title = ncurses_set_window_title;
249    kk->driver.get_window_width = ncurses_get_window_width;
250    kk->driver.get_window_height = ncurses_get_window_height;
251    kk->driver.display = ncurses_display;
252    kk->driver.handle_resize = ncurses_handle_resize;
253}
254
255#endif /* USE_NCURSES */
256
Note: See TracBrowser for help on using the repository browser.