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

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