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

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