source: libcaca/branches/0.5/src/caca.c @ 4104

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