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

Last change on this file since 331 was 331, checked in by Sam Hocevar, 17 years ago
  • test/event.c: + Do not refresh after each event, but only when there is no event

pending.

+ If the pressed key is a printable character, display it.

  • src/time.c: + Moved _caca_getticks() to this file.
  • src/caca.c: + Set the escape delay to a very low value in the ncurses driver,

because I don't want escape sequences to be entered manually.

  • src/io.c: + Autorepeat emulation in the ncurses and slang drivers: do not

immediately send the key release event.

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