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

Last change on this file since 305 was 305, checked in by Sam Hocevar, 17 years ago
  • src/ examples/ test/: + Changed <const type> constructs into <type const>.
  • Property svn:keywords set to Id
File size: 13.1 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 305 2004-01-02 16:52:10Z 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    /* Nothing to do */
150#endif
151    {
152        /* Dummy */
153    }
154
155    if(_caca_init_graphics())
156        return -1;
157
158    return 0;
159}
160
161/** \brief Get the screen width.
162 *
163 *  This function returns the current screen width, in character cells.
164 *
165 *  \return The screen width.
166 */
167unsigned int caca_get_width(void)
168{
169    return _caca_width;
170}
171
172/** \brief Get the screen height.
173 *
174 *  This function returns the current screen height, in character cells.
175 *
176 *  \return The screen height.
177 */
178unsigned int caca_get_height(void)
179{
180    return _caca_height;
181}
182
183/** \brief Translate a colour index into the colour's name.
184 *
185 *  This function translates a caca_color enum into a human-readable
186 *  description string of the associated colour.
187 *
188 *  \param color The colour value.
189 *  \return A static string containing the colour's name.
190 */
191char const *caca_get_color_name(enum caca_color color)
192{
193    static char const *color_names[] =
194    {
195        "black",
196        "blue",
197        "green",
198        "cyan",
199        "red",
200        "magenta",
201        "brown",
202        "light gray",
203        "dark gray",
204        "light blue",
205        "light green",
206        "light cyan",
207        "light red",
208        "light magenta",
209        "yellow",
210        "white",
211    };
212
213    if(color < 0 || color > 15)
214        return "unknown";
215
216    return color_names[color];
217}
218
219/** \brief Get the current value of a feature.
220 *
221 *  This function retrieves the value of an internal \e libcaca feature. A
222 *  generic feature value is expected, such as CACA_ANTIALIASING.
223 *
224 *  \param feature The requested feature.
225 *  \return The current value of the feature or CACA_UNKNOWN_FEATURE if an
226 *          error occurred..
227 */
228enum caca_feature caca_get_feature(enum caca_feature feature)
229{
230    switch(feature)
231    {
232        case CACA_BACKGROUND:
233            return _caca_background;
234        case CACA_ANTIALIASING:
235            return _caca_antialiasing;
236        case CACA_DITHERING:
237            return _caca_dithering;
238
239        default:
240            return CACA_UNKNOWN_FEATURE;
241    }
242}
243
244/** \brief Set a feature.
245 *
246 *  This function sets an internal \e libcaca feature such as the antialiasing
247 *  or dithering modes. If a specific feature such as CACA_DITHERING_RANDOM,
248 *  caca_set_feature() will set it immediately. If a generic feature is given
249 *  instead, such as CACA_DITHERING, the default value will be used instead.
250 *
251 *  \param feature The requested feature.
252 */
253void caca_set_feature(enum caca_feature feature)
254{
255    switch(feature)
256    {
257        case CACA_BACKGROUND:
258            feature = CACA_BACKGROUND_SOLID;
259        case CACA_BACKGROUND_BLACK:
260        case CACA_BACKGROUND_SOLID:
261            _caca_background = feature;
262            break;
263
264        case CACA_ANTIALIASING:
265            feature = CACA_ANTIALIASING_PREFILTER;
266        case CACA_ANTIALIASING_NONE:
267        case CACA_ANTIALIASING_PREFILTER:
268            _caca_antialiasing = feature;
269            break;
270
271        case CACA_DITHERING:
272            feature = CACA_DITHERING_ORDERED4;
273        case CACA_DITHERING_NONE:
274        case CACA_DITHERING_ORDERED2:
275        case CACA_DITHERING_ORDERED4:
276        case CACA_DITHERING_ORDERED8:
277        case CACA_DITHERING_RANDOM:
278            _caca_dithering = feature;
279            break;
280
281        case CACA_UNKNOWN_FEATURE:
282            break;
283    }
284}
285
286/** \brief Translate a feature value into the feature's name.
287 *
288 *  This function translates a caca_feature enum into a human-readable
289 *  description string of the associated feature.
290 *
291 *  \param feature The feature value.
292 *  \return A static string containing the feature's name.
293 */
294char const *caca_get_feature_name(enum caca_feature feature)
295{
296    switch(feature)
297    {
298        case CACA_BACKGROUND_BLACK: return "black background";
299        case CACA_BACKGROUND_SOLID: return "solid background";
300
301        case CACA_ANTIALIASING_NONE:      return "no antialiasing";
302        case CACA_ANTIALIASING_PREFILTER: return "prefilter antialiasing";
303
304        case CACA_DITHERING_NONE:     return "no dithering";
305        case CACA_DITHERING_ORDERED2: return "2x2 ordered dithering";
306        case CACA_DITHERING_ORDERED4: return "4x4 ordered dithering";
307        case CACA_DITHERING_ORDERED8: return "8x8 ordered dithering";
308        case CACA_DITHERING_RANDOM:   return "random dithering";
309
310        default: return "unknown";
311    }
312}
313
314/** \brief Uninitialise \e libcaca.
315 *
316 *  This function frees all resources allocated by caca_init(). After
317 *  caca_end() has been called, no other \e libcaca functions may be used
318 *  unless a new call to caca_init() is done.
319 */
320void caca_end(void)
321{
322    _caca_end_graphics();
323
324#if defined(USE_SLANG)
325    if(_caca_driver == CACA_DRIVER_SLANG)
326    {
327        SLtt_set_mouse_mode(0, 0);
328        SLtt_set_cursor_visibility(1);
329        SLang_reset_tty();
330        SLsmg_reset_smg();
331    }
332    else
333#endif
334#if defined(USE_NCURSES)
335    if(_caca_driver == CACA_DRIVER_NCURSES)
336    {
337        mousemask(oldmask, NULL);
338        curs_set(1);
339        endwin();
340    }
341    else
342#endif
343#if defined(USE_CONIO)
344    if(_caca_driver == CACA_DRIVER_CONIO)
345    {
346        _wscroll = 1;
347        textcolor((enum COLORS)WHITE);
348        textbackground((enum COLORS)BLACK);
349        gotoxy(_caca_width, _caca_height);
350        cputs("\r\n");
351        _setcursortype(_NORMALCURSOR);
352    }
353    else
354#endif
355#if defined(USE_X11)
356    if(_caca_driver == CACA_DRIVER_X11)
357    {
358        /* Nothing to do */
359    }
360    else
361#endif
362    {
363        /* Dummy */
364    }
365}
366
367/*
368 * XXX: The following functions are local.
369 */
370
371static void caca_init_driver(void)
372{
373#if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP)
374    char *var = getenv("CACA_DRIVER");
375
376    /* If the environment variable was set, use it */
377    if(var && *var)
378    {
379#if defined(USE_CONIO)
380        if(!strcasecmp(var, "conio"))
381            _caca_driver = CACA_DRIVER_CONIO;
382        else
383#endif
384#if defined(USE_X11)
385        if(!strcasecmp(var, "x11"))
386            _caca_driver = CACA_DRIVER_X11;
387        else
388#endif
389#if defined(USE_SLANG)
390        if(!strcasecmp(var, "slang"))
391            _caca_driver = CACA_DRIVER_SLANG;
392        else
393#endif
394#if defined(USE_NCURSES)
395        if(!strcasecmp(var, "ncurses"))
396            _caca_driver = CACA_DRIVER_NCURSES;
397        else
398#endif
399            _caca_driver = CACA_DRIVER_NONE;
400
401        return;
402    }
403#endif
404
405#if defined(USE_CONIO)
406    _caca_driver = CACA_DRIVER_CONIO;
407    return;
408#endif
409#if defined(USE_X11)
410#if defined(HAVE_GETENV)
411    if(getenv("DISPLAY") && *(getenv("DISPLAY")))
412#endif
413    {
414        _caca_driver = CACA_DRIVER_X11;
415        return;
416    }
417#endif
418#if defined(USE_SLANG)
419    _caca_driver = CACA_DRIVER_SLANG;
420    return;
421#endif
422#if defined(USE_NCURSES)
423    _caca_driver = CACA_DRIVER_NCURSES;
424    return;
425#endif
426    _caca_driver = CACA_DRIVER_NONE;
427    return;
428}
429
430static void caca_init_features(void)
431{
432    /* FIXME: if strcasecmp isn't available, use strcmp */
433#if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP)
434    char *var;
435#endif
436
437    caca_set_feature(CACA_BACKGROUND);
438    caca_set_feature(CACA_ANTIALIASING);
439    caca_set_feature(CACA_DITHERING);
440
441#if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP)
442    if((var = getenv("CACA_BACKGROUND")) && *var)
443    {
444        if(!strcasecmp("black", var))
445            caca_set_feature(CACA_BACKGROUND_BLACK);
446        else if(!strcasecmp("solid", var))
447            caca_set_feature(CACA_BACKGROUND_SOLID);
448    }
449
450    if((var = getenv("CACA_ANTIALIASING")) && *var)
451    {
452        if(!strcasecmp("none", var))
453            caca_set_feature(CACA_ANTIALIASING_NONE);
454        else if(!strcasecmp("prefilter", var))
455            caca_set_feature(CACA_ANTIALIASING_PREFILTER);
456    }
457
458    if((var = getenv("CACA_DITHERING")) && *var)
459    {
460        if(!strcasecmp("none", var))
461            caca_set_feature(CACA_DITHERING_NONE);
462        else if(!strcasecmp("ordered2", var))
463            caca_set_feature(CACA_DITHERING_ORDERED2);
464        else if(!strcasecmp("ordered4", var))
465            caca_set_feature(CACA_DITHERING_ORDERED4);
466        else if(!strcasecmp("ordered8", var))
467            caca_set_feature(CACA_DITHERING_ORDERED8);
468        else if(!strcasecmp("random", var))
469            caca_set_feature(CACA_DITHERING_RANDOM);
470    }
471#endif
472}
473
474static void caca_init_terminal(void)
475{
476#if defined(HAVE_GETENV) && defined(HAVE_PUTENV)
477    char *term, *colorterm, *other;
478
479#if defined(USE_SLANG)
480    if(_caca_driver != CACA_DRIVER_SLANG)
481#endif
482#if defined(USE_NCURSES)
483    if(_caca_driver != CACA_DRIVER_NCURSES)
484#endif
485    return;
486
487    term = getenv("TERM");
488    colorterm = getenv("COLORTERM");
489
490    if(term && !strcmp(term, "xterm"))
491    {
492        /* If we are using gnome-terminal, it's really a 16 colour terminal */
493        if(colorterm && !strcmp(colorterm, "gnome-terminal"))
494        {
495#if defined(USE_NCURSES)
496            if(_caca_driver == CACA_DRIVER_NCURSES)
497            {
498                SCREEN *screen;
499                screen = newterm("xterm-16color", stdout, stdin);
500                if(screen == NULL)
501                    return;
502                endwin();
503            }
504#endif
505            (void)putenv("TERM=xterm-16color");
506            return;
507        }
508
509        /* Ditto if we are using Konsole */
510        other = getenv("KONSOLE_DCOP_SESSION");
511        if(other)
512        {
513#if defined(USE_NCURSES)
514            if(_caca_driver == CACA_DRIVER_NCURSES)
515            {
516                SCREEN *screen;
517                screen = newterm("xterm-16color", stdout, stdin);
518                if(screen == NULL)
519                    return;
520                endwin();
521            }
522#endif
523            (void)putenv("TERM=xterm-16color");
524            return;
525        }
526    }
527#endif
528}
529
Note: See TracBrowser for help on using the repository browser.