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

Last change on this file since 540 was 540, checked in by Sam Hocevar, 16 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
RevLine 
[35]1/*
[268]2 *  libcaca       ASCII-Art library
[527]3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
[268]4 *                All Rights Reserved
[35]5 *
[268]6 *  This library is free software; you can redistribute it and/or
[522]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.
[35]10 */
[17]11
[540]12/** \file driver_ncurses.c
[268]13 *  \version \$Id: driver_ncurses.c 540 2006-03-07 09:17:35Z sam $
14 *  \author Sam Hocevar <sam@zoy.org>
[540]15 *  \brief Ncurses driver
[205]16 *
[540]17 *  This file contains the libcaca Ncurses input and output driver
[205]18 */
19
[63]20#include "config.h"
21
[539]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
[226]30#include <stdio.h> /* BUFSIZ */
[147]31#include <string.h>
[17]32#include <stdlib.h>
[344]33#if defined(HAVE_UNISTD_H)
34#   include <unistd.h>
35#endif
[181]36#include <stdarg.h>
[17]37
[348]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
[185]45#include "caca.h"
46#include "caca_internals.h"
[524]47#include "cucul.h"
48#include "cucul_internals.h"
[17]49
[281]50/*
51 * Local functions
52 */
[540]53
[539]54#if defined(HAVE_SIGNAL)
[348]55static RETSIGTYPE sigwinch_handler(int);
[527]56static caca_t *sigwinch_kk; /* FIXME: we ought to get rid of this */
[348]57#endif
58
[540]59static int ncurses_init_graphics(caca_t *kk)
[539]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    };
[300]82
[539]83    mmask_t newmask;
84    int fg, bg, max;
[483]85
[539]86#if defined(HAVE_SIGNAL)
[524]87    sigwinch_kk = kk;
[348]88    signal(SIGWINCH, sigwinch_handler);
89#endif
90
[539]91    initscr();
92    keypad(stdscr, TRUE);
93    nonl();
94    raw();
95    noecho();
96    nodelay(stdscr, TRUE);
97    curs_set(0);
[227]98
[539]99    /* Activate mouse */
100    newmask = REPORT_MOUSE_POSITION | ALL_MOUSE_EVENTS;
101    mousemask(newmask, &kk->ncurses.oldmask);
102    mouseinterval(-1); /* No click emulation */
[231]103
[539]104    /* Set the escape delay to a ridiculously low value */
105    ESCDELAY = 10;
[227]106
[539]107    /* Activate colour */
108    start_color();
[227]109
[539]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;
[227]117
[539]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);
[227]127
[539]128            if(max == 8)
[265]129            {
[539]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
[263]137                                                        | COLOR_PAIR(col);
[227]138            }
[265]139        }
[263]140
[539]141    cucul_set_size(kk->qq, COLS, LINES);
[300]142
[227]143    return 0;
144}
145
[540]146static int ncurses_end_graphics(caca_t *kk)
[251]147{
[539]148    mousemask(kk->ncurses.oldmask, NULL);
149    curs_set(1);
150    noraw();
151    endwin();
[300]152
[251]153    return 0;
154}
155
[540]156static int ncurses_set_window_title(caca_t *kk, char const *title)
[343]157{
158    return 0;
159}
160
[540]161static unsigned int ncurses_get_window_width(caca_t *kk)
[352]162{
163    /* Fallback to a 6x10 font */
[524]164    return kk->qq->width * 6;
[352]165}
166
[540]167static unsigned int ncurses_get_window_height(caca_t *kk)
[352]168{
169    /* Fallback to a 6x10 font */
[524]170    return kk->qq->height * 10;
[352]171}
172
[540]173static void ncurses_display(caca_t *kk)
[227]174{
[539]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++)
[265]179    {
[539]180        move(y, 0);
181        for(x = kk->qq->width; x--; )
[527]182        {
[539]183            attrset(kk->ncurses.attr[*attr++]);
184            addch(*chars++ & 0x7f);
[527]185        }
[265]186    }
[539]187    refresh();
[227]188}
189
[540]190static void ncurses_handle_resize(caca_t *kk, unsigned int *new_width,
191                                              unsigned int *new_height)
[347]192{
[539]193    struct winsize size;
[347]194
[540]195    *new_width = kk->qq->width;
196    *new_height = kk->qq->height;
[527]197
[539]198    if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0)
[347]199    {
[540]200        *new_width = size.ws_col;
201        *new_height = size.ws_row;
[364]202#if defined(HAVE_RESIZE_TERM)
[540]203        resize_term(*new_height, *new_width);
[364]204#else
[540]205        resizeterm(*new_height, *new_width);
[364]206#endif
[539]207        wrefresh(curscr);
[347]208    }
209}
210
[539]211/*
212 * XXX: following functions are local
213 */
[281]214
[539]215#if defined(HAVE_SIGNAL)
[348]216static RETSIGTYPE sigwinch_handler(int sig)
217{
[524]218    sigwinch_kk->resize_event = 1;
[348]219
220    signal(SIGWINCH, sigwinch_handler);;
221}
222#endif
223
[539]224/*
225 * Driver initialisation
226 */
[527]227
[539]228void ncurses_init_driver(caca_t *kk)
[511]229{
[539]230    kk->driver.driver = CACA_DRIVER_NCURSES;
[527]231
[539]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;
[511]239}
240
[539]241#endif /* USE_NCURSES */
[527]242
Note: See TracBrowser for help on using the repository browser.