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

Last change on this file since 291 was 291, checked in by Sam Hocevar, 17 years ago
  • src/caca.c: + Do not try the X11 driver if DISPLAY is set to the empty string.
  • examples/cacaview.c: + Cosmetic fixes.
  • Property svn:keywords set to Id
File size: 13.0 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 291 2003-12-31 12:05: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#   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_X11)
384        if(!strcasecmp(var, "x11"))
385            _caca_driver = CACA_DRIVER_X11;
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_NCURSES)
394        if(!strcasecmp(var, "ncurses"))
395            _caca_driver = CACA_DRIVER_NCURSES;
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_X11)
409#if defined(HAVE_GETENV)
410    if(getenv("DISPLAY") && *(getenv("DISPLAY")))
411#endif
412    {
413        _caca_driver = CACA_DRIVER_X11;
414        return;
415    }
416#endif
417#if defined(USE_SLANG)
418    _caca_driver = CACA_DRIVER_SLANG;
419    return;
420#endif
421#if defined(USE_NCURSES)
422    _caca_driver = CACA_DRIVER_NCURSES;
423    return;
424#endif
425    _caca_driver = CACA_DRIVER_NONE;
426    return;
427}
428
429static void caca_init_features(void)
430{
431    /* FIXME: if strcasecmp isn't available, use strcmp */
432#if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP)
433    char *var;
434#endif
435
436    caca_set_feature(CACA_BACKGROUND);
437    caca_set_feature(CACA_ANTIALIASING);
438    caca_set_feature(CACA_DITHERING);
439
440#if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP)
441    if((var = getenv("CACA_BACKGROUND")))
442    {
443        if(!strcasecmp("black", var))
444            caca_set_feature(CACA_BACKGROUND_BLACK);
445        else if(!strcasecmp("solid", var))
446            caca_set_feature(CACA_BACKGROUND_SOLID);
447    }
448
449    if((var = getenv("CACA_ANTIALIASING")))
450    {
451        if(!strcasecmp("none", var))
452            caca_set_feature(CACA_ANTIALIASING_NONE);
453        else if(!strcasecmp("prefilter", var))
454            caca_set_feature(CACA_ANTIALIASING_PREFILTER);
455    }
456
457    if((var = getenv("CACA_DITHERING")))
458    {
459        if(!strcasecmp("none", var))
460            caca_set_feature(CACA_DITHERING_NONE);
461        else if(!strcasecmp("ordered2", var))
462            caca_set_feature(CACA_DITHERING_ORDERED2);
463        else if(!strcasecmp("ordered4", var))
464            caca_set_feature(CACA_DITHERING_ORDERED4);
465        else if(!strcasecmp("ordered8", var))
466            caca_set_feature(CACA_DITHERING_ORDERED8);
467        else if(!strcasecmp("random", var))
468            caca_set_feature(CACA_DITHERING_RANDOM);
469    }
470#endif
471}
472
473static void caca_init_terminal(void)
474{
475#if defined(HAVE_GETENV) && defined(HAVE_PUTENV)
476    char *term, *colorterm, *other;
477
478#if defined(USE_SLANG)
479    if(_caca_driver != CACA_DRIVER_SLANG)
480#endif
481#if defined(USE_NCURSES)
482    if(_caca_driver != CACA_DRIVER_NCURSES)
483#endif
484    return;
485
486    term = getenv("TERM");
487    colorterm = getenv("COLORTERM");
488
489    if(term && !strcmp(term, "xterm"))
490    {
491        /* If we are using gnome-terminal, it's really a 16 colour terminal */
492        if(colorterm && !strcmp(colorterm, "gnome-terminal"))
493        {
494#if defined(USE_NCURSES)
495            if(_caca_driver == CACA_DRIVER_NCURSES)
496            {
497                SCREEN *screen;
498                screen = newterm("xterm-16color", stdout, stdin);
499                if(screen == NULL)
500                    return;
501                endwin();
502            }
503#endif
504            (void)putenv("TERM=xterm-16color");
505            return;
506        }
507
508        /* Ditto if we are using Konsole */
509        other = getenv("KONSOLE_DCOP_SESSION");
510        if(other)
511        {
512#if defined(USE_NCURSES)
513            if(_caca_driver == CACA_DRIVER_NCURSES)
514            {
515                SCREEN *screen;
516                screen = newterm("xterm-16color", stdout, stdin);
517                if(screen == NULL)
518                    return;
519                endwin();
520            }
521#endif
522            (void)putenv("TERM=xterm-16color");
523            return;
524        }
525    }
526#endif
527}
528
Note: See TracBrowser for help on using the repository browser.