source: libcaca/trunk/src/caca.c @ 309

Last change on this file since 309 was 309, checked in by Sam Hocevar, 17 years ago
  • configure.ac: + Search for <slang/slang.h> in addition of <slang.h>.
  • Property svn:keywords set to Id
File size: 13.2 KB
Line 
1/*
2 *  libcaca       ASCII-Art library
3 *  Copyright (c) 2002, 2003 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 GNU Lesser General Public
8 *  License as published by the Free Software Foundation; either
9 *  version 2 of the License, or (at your option) any later version.
10 *
11 *  This library is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 *  Lesser General Public License for more details.
15 *
16 *  You should have received a copy of the GNU Lesser General Public
17 *  License along with this library; if not, write to the Free Software
18 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 *  02111-1307  USA
20 */
21
22/** \file caca.c
23 *  \version \$Id: caca.c 309 2004-01-03 17:31:44Z sam $
24 *  \author Sam Hocevar <sam@zoy.org>
25 *  \brief Main \e libcaca functions
26 *
27 *  This file contains the main functions used by \e libcaca applications to
28 *  initialise the library, get the screen properties, set the framerate and
29 *  so on.
30 */
31
32#include "config.h"
33
34#if defined(USE_SLANG)
35#   if defined(HAVE_SLANG_SLANG_H)
36#       include <slang/slang.h>
37#   else
38#       include <slang.h>
39#   endif
40#endif
41#if defined(USE_NCURSES)
42#   include <curses.h>
43#endif
44#if defined(USE_CONIO)
45#   include <dos.h>
46#   include <conio.h>
47#endif
48#if defined(USE_X11)
49#   include <X11/Xlib.h>
50#endif
51
52#include <stdlib.h>
53#include <string.h>
54
55#include "caca.h"
56#include "caca_internals.h"
57
58static void caca_init_driver(void);
59static void caca_init_features(void);
60static void caca_init_terminal(void);
61
62enum caca_driver _caca_driver;
63
64#if defined(USE_NCURSES)
65static mmask_t oldmask;
66#endif
67
68/** \brief Initialise \e libcaca.
69 *
70 *  This function initialises internal \e libcaca structures and the backend
71 *  that will be used for subsequent graphical operations. It must be the
72 *  first \e libcaca function to be called in a function. caca_end() should
73 *  be called at the end of the program to free all allocated resources.
74 *
75 *  \return 0 upon success, a non-zero value if an error occurs.
76 */
77int caca_init(void)
78{
79#if defined(USE_NCURSES)
80    mmask_t newmask;
81#endif
82
83    caca_init_driver();
84
85    if(_caca_driver == CACA_DRIVER_NONE)
86        return -1;
87
88    caca_init_features();
89    caca_init_terminal();
90
91#if defined(USE_SLANG)
92    if(_caca_driver == CACA_DRIVER_SLANG)
93    {
94        /* Initialise slang library */
95        SLsig_block_signals();
96        SLtt_get_terminfo();
97
98        if(SLkp_init() == -1)
99        {
100            SLsig_unblock_signals();
101            return -1;
102        }
103
104        SLang_init_tty(-1, 0, 1);
105
106        if(SLsmg_init_smg() == -1)
107        {
108            SLsig_unblock_signals();
109            return -1;
110        }
111
112        SLsig_unblock_signals();
113
114        SLsmg_cls();
115        SLtt_set_cursor_visibility(0);
116        SLkp_define_keysym("\e[M", 1001);
117        SLtt_set_mouse_mode(1, 0);
118        SLsmg_refresh();
119
120        /* Disable scrolling so that hashmap scrolling optimization code
121         * does not cause ugly refreshes due to slow terminals */
122        SLtt_Term_Cannot_Scroll = 1;
123    }
124    else
125#endif
126#if defined(USE_NCURSES)
127    if(_caca_driver == CACA_DRIVER_NCURSES)
128    {
129        initscr();
130        keypad(stdscr, TRUE);
131        nonl();
132        cbreak();
133        noecho();
134        nodelay(stdscr, TRUE);
135        curs_set(0);
136
137        /* Activate mouse */
138        newmask = ALL_MOUSE_EVENTS;
139        mousemask(newmask, &oldmask);
140    }
141    else
142#endif
143#if defined(USE_CONIO)
144    if(_caca_driver == CACA_DRIVER_CONIO)
145    {
146        _wscroll = 0;
147        _setcursortype(_NOCURSOR);
148        clrscr();
149    }
150    else
151#endif
152#if defined(USE_X11)
153    /* Nothing to do */
154#endif
155    {
156        /* Dummy */
157    }
158
159    if(_caca_init_graphics())
160        return -1;
161
162    if(_caca_init_bitmap())
163        return -1;
164
165    return 0;
166}
167
168/** \brief Get the screen width.
169 *
170 *  This function returns the current screen width, in character cells.
171 *
172 *  \return The screen width.
173 */
174unsigned int caca_get_width(void)
175{
176    return _caca_width;
177}
178
179/** \brief Get the screen height.
180 *
181 *  This function returns the current screen height, in character cells.
182 *
183 *  \return The screen height.
184 */
185unsigned int caca_get_height(void)
186{
187    return _caca_height;
188}
189
190/** \brief Translate a colour index into the colour's name.
191 *
192 *  This function translates a caca_color enum into a human-readable
193 *  description string of the associated colour.
194 *
195 *  \param color The colour value.
196 *  \return A static string containing the colour's name.
197 */
198char const *caca_get_color_name(enum caca_color color)
199{
200    static char const *color_names[] =
201    {
202        "black",
203        "blue",
204        "green",
205        "cyan",
206        "red",
207        "magenta",
208        "brown",
209        "light gray",
210        "dark gray",
211        "light blue",
212        "light green",
213        "light cyan",
214        "light red",
215        "light magenta",
216        "yellow",
217        "white",
218    };
219
220    if(color < 0 || color > 15)
221        return "unknown";
222
223    return color_names[color];
224}
225
226/** \brief Get the current value of a feature.
227 *
228 *  This function retrieves the value of an internal \e libcaca feature. A
229 *  generic feature value is expected, such as CACA_ANTIALIASING.
230 *
231 *  \param feature The requested feature.
232 *  \return The current value of the feature or CACA_UNKNOWN_FEATURE if an
233 *          error occurred..
234 */
235enum caca_feature caca_get_feature(enum caca_feature feature)
236{
237    switch(feature)
238    {
239        case CACA_BACKGROUND:
240            return _caca_background;
241        case CACA_ANTIALIASING:
242            return _caca_antialiasing;
243        case CACA_DITHERING:
244            return _caca_dithering;
245
246        default:
247            return CACA_UNKNOWN_FEATURE;
248    }
249}
250
251/** \brief Set a feature.
252 *
253 *  This function sets an internal \e libcaca feature such as the antialiasing
254 *  or dithering modes. If a specific feature such as CACA_DITHERING_RANDOM,
255 *  caca_set_feature() will set it immediately. If a generic feature is given
256 *  instead, such as CACA_DITHERING, the default value will be used instead.
257 *
258 *  \param feature The requested feature.
259 */
260void caca_set_feature(enum caca_feature feature)
261{
262    switch(feature)
263    {
264        case CACA_BACKGROUND:
265            feature = CACA_BACKGROUND_SOLID;
266        case CACA_BACKGROUND_BLACK:
267        case CACA_BACKGROUND_SOLID:
268            _caca_background = feature;
269            break;
270
271        case CACA_ANTIALIASING:
272            feature = CACA_ANTIALIASING_PREFILTER;
273        case CACA_ANTIALIASING_NONE:
274        case CACA_ANTIALIASING_PREFILTER:
275            _caca_antialiasing = feature;
276            break;
277
278        case CACA_DITHERING:
279            feature = CACA_DITHERING_ORDERED4;
280        case CACA_DITHERING_NONE:
281        case CACA_DITHERING_ORDERED2:
282        case CACA_DITHERING_ORDERED4:
283        case CACA_DITHERING_ORDERED8:
284        case CACA_DITHERING_RANDOM:
285            _caca_dithering = feature;
286            break;
287
288        case CACA_UNKNOWN_FEATURE:
289            break;
290    }
291}
292
293/** \brief Translate a feature value into the feature's name.
294 *
295 *  This function translates a caca_feature enum into a human-readable
296 *  description string of the associated feature.
297 *
298 *  \param feature The feature value.
299 *  \return A static string containing the feature's name.
300 */
301char const *caca_get_feature_name(enum caca_feature feature)
302{
303    switch(feature)
304    {
305        case CACA_BACKGROUND_BLACK: return "black background";
306        case CACA_BACKGROUND_SOLID: return "solid background";
307
308        case CACA_ANTIALIASING_NONE:      return "no antialiasing";
309        case CACA_ANTIALIASING_PREFILTER: return "prefilter antialiasing";
310
311        case CACA_DITHERING_NONE:     return "no dithering";
312        case CACA_DITHERING_ORDERED2: return "2x2 ordered dithering";
313        case CACA_DITHERING_ORDERED4: return "4x4 ordered dithering";
314        case CACA_DITHERING_ORDERED8: return "8x8 ordered dithering";
315        case CACA_DITHERING_RANDOM:   return "random dithering";
316
317        default: return "unknown";
318    }
319}
320
321/** \brief Uninitialise \e libcaca.
322 *
323 *  This function frees all resources allocated by caca_init(). After
324 *  caca_end() has been called, no other \e libcaca functions may be used
325 *  unless a new call to caca_init() is done.
326 */
327void caca_end(void)
328{
329    _caca_end_bitmap();
330    _caca_end_graphics();
331
332#if defined(USE_SLANG)
333    if(_caca_driver == CACA_DRIVER_SLANG)
334    {
335        SLtt_set_mouse_mode(0, 0);
336        SLtt_set_cursor_visibility(1);
337        SLang_reset_tty();
338        SLsmg_reset_smg();
339    }
340    else
341#endif
342#if defined(USE_NCURSES)
343    if(_caca_driver == CACA_DRIVER_NCURSES)
344    {
345        mousemask(oldmask, NULL);
346        curs_set(1);
347        endwin();
348    }
349    else
350#endif
351#if defined(USE_CONIO)
352    if(_caca_driver == CACA_DRIVER_CONIO)
353    {
354        _wscroll = 1;
355        textcolor((enum COLORS)WHITE);
356        textbackground((enum COLORS)BLACK);
357        gotoxy(_caca_width, _caca_height);
358        cputs("\r\n");
359        _setcursortype(_NORMALCURSOR);
360    }
361    else
362#endif
363#if defined(USE_X11)
364    if(_caca_driver == CACA_DRIVER_X11)
365    {
366        /* Nothing to do */
367    }
368    else
369#endif
370    {
371        /* Dummy */
372    }
373}
374
375/*
376 * XXX: The following functions are local.
377 */
378
379static void caca_init_driver(void)
380{
381#if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP)
382    char *var = getenv("CACA_DRIVER");
383
384    /* If the environment variable was set, use it */
385    if(var && *var)
386    {
387#if defined(USE_CONIO)
388        if(!strcasecmp(var, "conio"))
389            _caca_driver = CACA_DRIVER_CONIO;
390        else
391#endif
392#if defined(USE_X11)
393        if(!strcasecmp(var, "x11"))
394            _caca_driver = CACA_DRIVER_X11;
395        else
396#endif
397#if defined(USE_SLANG)
398        if(!strcasecmp(var, "slang"))
399            _caca_driver = CACA_DRIVER_SLANG;
400        else
401#endif
402#if defined(USE_NCURSES)
403        if(!strcasecmp(var, "ncurses"))
404            _caca_driver = CACA_DRIVER_NCURSES;
405        else
406#endif
407            _caca_driver = CACA_DRIVER_NONE;
408
409        return;
410    }
411#endif
412
413#if defined(USE_CONIO)
414    _caca_driver = CACA_DRIVER_CONIO;
415    return;
416#endif
417#if defined(USE_X11)
418#if defined(HAVE_GETENV)
419    if(getenv("DISPLAY") && *(getenv("DISPLAY")))
420#endif
421    {
422        _caca_driver = CACA_DRIVER_X11;
423        return;
424    }
425#endif
426#if defined(USE_SLANG)
427    _caca_driver = CACA_DRIVER_SLANG;
428    return;
429#endif
430#if defined(USE_NCURSES)
431    _caca_driver = CACA_DRIVER_NCURSES;
432    return;
433#endif
434    _caca_driver = CACA_DRIVER_NONE;
435    return;
436}
437
438static void caca_init_features(void)
439{
440    /* FIXME: if strcasecmp isn't available, use strcmp */
441#if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP)
442    char *var;
443#endif
444
445    caca_set_feature(CACA_BACKGROUND);
446    caca_set_feature(CACA_ANTIALIASING);
447    caca_set_feature(CACA_DITHERING);
448
449#if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP)
450    if((var = getenv("CACA_BACKGROUND")) && *var)
451    {
452        if(!strcasecmp("black", var))
453            caca_set_feature(CACA_BACKGROUND_BLACK);
454        else if(!strcasecmp("solid", var))
455            caca_set_feature(CACA_BACKGROUND_SOLID);
456    }
457
458    if((var = getenv("CACA_ANTIALIASING")) && *var)
459    {
460        if(!strcasecmp("none", var))
461            caca_set_feature(CACA_ANTIALIASING_NONE);
462        else if(!strcasecmp("prefilter", var))
463            caca_set_feature(CACA_ANTIALIASING_PREFILTER);
464    }
465
466    if((var = getenv("CACA_DITHERING")) && *var)
467    {
468        if(!strcasecmp("none", var))
469            caca_set_feature(CACA_DITHERING_NONE);
470        else if(!strcasecmp("ordered2", var))
471            caca_set_feature(CACA_DITHERING_ORDERED2);
472        else if(!strcasecmp("ordered4", var))
473            caca_set_feature(CACA_DITHERING_ORDERED4);
474        else if(!strcasecmp("ordered8", var))
475            caca_set_feature(CACA_DITHERING_ORDERED8);
476        else if(!strcasecmp("random", var))
477            caca_set_feature(CACA_DITHERING_RANDOM);
478    }
479#endif
480}
481
482static void caca_init_terminal(void)
483{
484#if defined(HAVE_GETENV) && defined(HAVE_PUTENV)
485    char *term, *colorterm, *other;
486
487#if defined(USE_SLANG)
488    if(_caca_driver != CACA_DRIVER_SLANG)
489#endif
490#if defined(USE_NCURSES)
491    if(_caca_driver != CACA_DRIVER_NCURSES)
492#endif
493    return;
494
495    term = getenv("TERM");
496    colorterm = getenv("COLORTERM");
497
498    if(term && !strcmp(term, "xterm"))
499    {
500        /* If we are using gnome-terminal, it's really a 16 colour terminal */
501        if(colorterm && !strcmp(colorterm, "gnome-terminal"))
502        {
503#if defined(USE_NCURSES)
504            if(_caca_driver == CACA_DRIVER_NCURSES)
505            {
506                SCREEN *screen;
507                screen = newterm("xterm-16color", stdout, stdin);
508                if(screen == NULL)
509                    return;
510                endwin();
511            }
512#endif
513            (void)putenv("TERM=xterm-16color");
514            return;
515        }
516
517        /* Ditto if we are using Konsole */
518        other = getenv("KONSOLE_DCOP_SESSION");
519        if(other)
520        {
521#if defined(USE_NCURSES)
522            if(_caca_driver == CACA_DRIVER_NCURSES)
523            {
524                SCREEN *screen;
525                screen = newterm("xterm-16color", stdout, stdin);
526                if(screen == NULL)
527                    return;
528                endwin();
529            }
530#endif
531            (void)putenv("TERM=xterm-16color");
532            return;
533        }
534    }
535#endif
536}
537
Note: See TracBrowser for help on using the repository browser.