source: libcaca/branches/0.9/src/caca.c @ 3583

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