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

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