source: libcaca/trunk/src/graphics.c @ 270

Last change on this file since 270 was 270, checked in by Sam Hocevar, 16 years ago
  • configure.ac NEWS: + Prepared release 0.4.
  • src/graphics.c README BUGS TODO: + Updated documentation.
  • Makefile.am doc/Makefile.am: + Install the generated doxygen documentation.
  • Property svn:keywords set to Id
File size: 21.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 graphics.c
23 *  \version \$Id: graphics.c 270 2003-12-23 17:01:38Z sam $
24 *  \author Sam Hocevar <sam@zoy.org>
25 *  \brief Character drawing functions
26 *
27 *  This file contains character and string drawing functions.
28 */
29
30#include "config.h"
31
32#if defined(USE_SLANG)
33#   include <slang.h>
34#endif
35#if defined(USE_NCURSES)
36#   include <curses.h>
37#endif
38#if defined(USE_CONIO)
39#   include <conio.h>
40#   if defined(SCREENUPDATE_IN_PC_H)
41#       include <pc.h>
42#   endif
43#endif
44#if defined(USE_X11)
45#   include <X11/Xlib.h>
46#endif
47
48#if defined(HAVE_INTTYPES_H)
49#   include <inttypes.h>
50#endif
51
52#include <stdio.h> /* BUFSIZ */
53#include <string.h>
54#include <stdlib.h>
55#include <unistd.h>
56#include <stdarg.h>
57#include <sys/time.h>
58#include <time.h>
59
60#include "caca.h"
61#include "caca_internals.h"
62
63/*
64 * Global variables
65 */
66unsigned int _caca_width = 0;
67unsigned int _caca_height = 0;
68
69/*
70 * Local variables
71 */
72#if defined(USE_NCURSES)
73static int ncurses_attr[16*16];
74#endif
75
76#if defined(USE_CONIO)
77static struct text_info conio_ti;
78static char *conio_screen;
79#endif
80
81#if defined(USE_X11)
82Display *x11_dpy;
83Window x11_window;
84static GC x11_gc;
85static Pixmap x11_pixmap;
86static int *x11_screen;
87static int x11_colors[16];
88static Font x11_font;
89static XFontStruct *x11_font_struct;
90static int x11_font_width, x11_font_height, x11_font_offset;
91#endif
92
93static char *_caca_empty_line;
94static char *_caca_scratch_line;
95
96static unsigned int _caca_delay;
97static unsigned int _caca_rendertime;
98
99static enum caca_color _caca_fgcolor = CACA_COLOR_LIGHTGRAY;
100static enum caca_color _caca_bgcolor = CACA_COLOR_BLACK;
101
102/** \brief Set the default colour pair.
103 *
104 *  This function sets the default colour pair. String functions such as
105 *  caca_printf() and graphical primitive functions such as caca_draw_line()
106 *  will use these colour pairs.
107 *
108 *  \param fgcolor The requested foreground colour.
109 *  \param bgcolor The requested background colour.
110 */
111void caca_set_color(enum caca_color fgcolor, enum caca_color bgcolor)
112{
113    if(fgcolor < 0 || fgcolor > 15 || bgcolor < 0 || bgcolor > 15)
114        return;
115
116    _caca_fgcolor = fgcolor;
117    _caca_bgcolor = bgcolor;
118    switch(_caca_driver)
119    {
120#if defined(USE_SLANG)
121    case CACA_DRIVER_SLANG:
122        SLsmg_set_color((bgcolor + 16 * fgcolor) /*% 128*/);
123        break;
124#endif
125#if defined(USE_NCURSES)
126    case CACA_DRIVER_NCURSES:
127        attrset(ncurses_attr[fgcolor + 16 * bgcolor]);
128        break;
129#endif
130#if defined(USE_CONIO)
131    case CACA_DRIVER_CONIO:
132        textbackground(bgcolor);
133        textcolor(fgcolor);
134        break;
135#endif
136#if defined(USE_X11)
137    case CACA_DRIVER_X11:
138        /* FIXME */
139        break;
140#endif
141    default:
142        break;
143    }
144}
145
146/** \brief Get the current foreground colour.
147 *
148 *  This function returns the current foreground colour that was set with
149 *  caca_set_color().
150 *
151 *  \return The current foreground colour.
152 */
153enum caca_color caca_get_fg_color(void)
154{
155    return _caca_fgcolor;
156}
157
158/** \brief Get the current background colour.
159 *
160 *  This function returns the current background colour that was set with
161 *  caca_set_color().
162 *
163 *  \return The current background colour.
164 */
165enum caca_color caca_get_bg_color(void)
166{
167    return _caca_bgcolor;
168}
169
170/** \brief Print a character.
171 *
172 *  This function prints a character at the given coordinates, using the
173 *  default foreground and background values. If the coordinates are outside
174 *  the screen boundaries, nothing is printed.
175 *
176 *  \param x X coordinate.
177 *  \param y Y coordinate.
178 *  \param c The character to print.
179 */
180void caca_putchar(int x, int y, char c)
181{
182#if defined(USE_CONIO)
183    char *data;
184#endif
185    if(x < 0 || x >= (int)_caca_width ||
186       y < 0 || y >= (int)_caca_height)
187        return;
188
189    switch(_caca_driver)
190    {
191#if defined(USE_SLANG)
192    case CACA_DRIVER_SLANG:
193        SLsmg_gotorc(y, x);
194        SLsmg_write_char(c);
195        break;
196#endif
197#if defined(USE_NCURSES)
198    case CACA_DRIVER_NCURSES:
199        move(y, x);
200        addch(c);
201        break;
202#endif
203#if defined(USE_CONIO)
204    case CACA_DRIVER_CONIO:
205        data = conio_screen + 2 * (x + y * _caca_width);
206        data[0] = c;
207        data[1] = (_caca_bgcolor << 4) | _caca_fgcolor;
208//        gotoxy(x + 1, y + 1);
209//        putch(c);
210        break;
211#endif
212#if defined(USE_X11)
213    case CACA_DRIVER_X11:
214        x11_screen[x + y * _caca_width] =
215            ((int)c << 8) | ((int)_caca_bgcolor << 4) | (int)_caca_fgcolor;
216        break;
217#endif
218    default:
219        break;
220    }
221}
222
223/** \brief Print a string.
224 *
225 *  This function prints a string at the given coordinates, using the
226 *  default foreground and background values. The coordinates may be outside
227 *  the screen boundaries (eg. a negative Y coordinate) and the string will
228 *  be cropped accordingly if it is too long.
229 *
230 *  \param x X coordinate.
231 *  \param y Y coordinate.
232 *  \param s The string to print.
233 */
234void caca_putstr(int x, int y, const char *s)
235{
236#if defined(USE_CONIO)
237    char *charbuf;
238#endif
239#if defined(USE_X11)
240    int *intbuf;
241#endif
242    unsigned int len;
243
244    if(y < 0 || y >= (int)_caca_height || x >= (int)_caca_width)
245        return;
246
247    len = strlen(s);
248
249    if(x < 0)
250    {
251        len -= -x;
252        if(len < 0)
253            return;
254        s += -x;
255        x = 0;
256    }
257
258    if(x + len >= _caca_width)
259    {
260        memcpy(_caca_scratch_line, s, _caca_width - x);
261        _caca_scratch_line[_caca_width - x] = '\0';
262        s = _caca_scratch_line;
263    }
264
265    switch(_caca_driver)
266    {
267#if defined(USE_SLANG)
268    case CACA_DRIVER_SLANG:
269        SLsmg_gotorc(y, x);
270        SLsmg_write_string((char *)(intptr_t)s);
271        break;
272#endif
273#if defined(USE_NCURSES)
274    case CACA_DRIVER_NCURSES:
275        move(y, x);
276        addstr(s);
277        break;
278#endif
279#if defined(USE_CONIO)
280    case CACA_DRIVER_CONIO:
281        charbuf = conio_screen + 2 * (x + y * _caca_width);
282        while(*s)
283        {
284            *charbuf++ = *s++;
285            *charbuf++ = (_caca_bgcolor << 4) | _caca_fgcolor;
286        }
287//        gotoxy(x + 1, y + 1);
288//        cputs(s);
289        break;
290#endif
291#if defined(USE_X11)
292    case CACA_DRIVER_X11:
293        intbuf = x11_screen + x + y * _caca_width;
294        while(*s)
295            *intbuf++ = ((int)*s++ << 8)
296                         | ((int)_caca_bgcolor << 4) | (int)_caca_fgcolor;
297        break;
298#endif
299    default:
300        break;
301    }
302}
303
304/** \brief Format a string.
305 *
306 *  This function formats a string at the given coordinates, using the
307 *  default foreground and background values. The coordinates may be outside
308 *  the screen boundaries (eg. a negative Y coordinate) and the string will
309 *  be cropped accordingly if it is too long. The syntax of the format
310 *  string is the same as for the C printf() function.
311 *
312 *  \param x X coordinate.
313 *  \param y Y coordinate.
314 *  \param format The format string to print.
315 *  \param ... Arguments to the format string.
316 */
317void caca_printf(int x, int y, const char *format, ...)
318{
319    char tmp[BUFSIZ];
320    char *buf = tmp;
321    va_list args;
322
323    if(y < 0 || y >= (int)_caca_height || x >= (int)_caca_width)
324        return;
325
326    if(_caca_width - x + 1 > BUFSIZ)
327        buf = malloc(_caca_width - x + 1);
328
329    va_start(args, format);
330#if defined(HAVE_VSNPRINTF)
331    vsnprintf(buf, _caca_width - x + 1, format, args);
332#else
333    vsprintf(buf, format, args);
334#endif
335    buf[_caca_width - x] = '\0';
336    va_end(args);
337
338    caca_putstr(x, y, buf);
339
340    if(buf != tmp)
341        free(buf);
342}
343
344/** \brief Clear the screen.
345 *
346 *  This function clears the screen using a black background.
347 */
348void caca_clear(void)
349{
350    enum caca_color oldfg = caca_get_fg_color();
351    enum caca_color oldbg = caca_get_bg_color();
352    int y = _caca_height;
353
354    caca_set_color(CACA_COLOR_LIGHTGRAY, CACA_COLOR_BLACK);
355
356    /* We could use SLsmg_cls() etc., but drawing empty lines is much faster */
357    while(y--)
358        caca_putstr(0, y, _caca_empty_line);
359
360    caca_set_color(oldfg, oldbg);
361}
362
363int _caca_init_graphics(void)
364{
365#if defined(USE_SLANG)
366    if(_caca_driver == CACA_DRIVER_SLANG)
367    {
368        /* See SLang ref., 5.4.4. */
369        static char *slang_colors[16] =
370        {
371            /* Standard colours */
372            "black",
373            "blue",
374            "green",
375            "cyan",
376            "red",
377            "magenta",
378            "brown",
379            "lightgray",
380            /* Bright colours */
381            "gray",
382            "brightblue",
383            "brightgreen",
384            "brightcyan",
385            "brightred",
386            "brightmagenta",
387            "yellow",
388            "white",
389        };
390
391        int fg, bg;
392
393        for(fg = 0; fg < 16; fg++)
394            for(bg = 0; bg < 16; bg++)
395            {
396                int i = bg + 16 * fg;
397                SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]);
398            }
399
400        /* Disable alt charset support so that we get all 256 colour pairs */
401        SLtt_Has_Alt_Charset = 0;
402
403        _caca_width = SLtt_Screen_Cols;
404        _caca_height = SLtt_Screen_Rows;
405    }
406    else
407#endif
408#if defined(USE_NCURSES)
409    if(_caca_driver == CACA_DRIVER_NCURSES)
410    {
411        static int curses_colors[] =
412        {
413            /* Standard curses colours */
414            COLOR_BLACK,
415            COLOR_BLUE,
416            COLOR_GREEN,
417            COLOR_CYAN,
418            COLOR_RED,
419            COLOR_MAGENTA,
420            COLOR_YELLOW,
421            COLOR_WHITE,
422            /* Extra values for xterm-16color */
423            COLOR_BLACK + 8,
424            COLOR_BLUE + 8,
425            COLOR_GREEN + 8,
426            COLOR_CYAN + 8,
427            COLOR_RED + 8,
428            COLOR_MAGENTA + 8,
429            COLOR_YELLOW + 8,
430            COLOR_WHITE + 8
431        };
432
433        int fg, bg, max;
434
435        /* Activate colour */
436        start_color();
437
438        /* If COLORS == 16, it means the terminal supports full bright colours
439         * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
440         * we can build 16*16 colour pairs.
441         * If COLORS == 8, it means the terminal does not know about bright
442         * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
443         * and \e[5m). We can only build 8*8 colour pairs. */
444        max = COLORS >= 16 ? 16 : 8;
445
446        for(bg = 0; bg < max; bg++)
447            for(fg = 0; fg < max; fg++)
448            {
449                /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
450                 * is light gray on black, since some terminals don't like
451                 * this colour pair to be redefined. */
452                int col = ((max + 7 - fg) % max) + max * bg;
453                init_pair(col, curses_colors[fg], curses_colors[bg]);
454                ncurses_attr[fg + 16 * bg] = COLOR_PAIR(col);
455
456                if(max == 8)
457                {
458                    /* Bright fg on simple bg */
459                    ncurses_attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
460                    /* Simple fg on bright bg */
461                    ncurses_attr[fg + 16 * (bg + 8)] = A_BLINK
462                                                        | COLOR_PAIR(col);
463                    /* Bright fg on bright bg */
464                    ncurses_attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
465                                                            | COLOR_PAIR(col);
466                }
467            }
468
469        _caca_width = COLS;
470        _caca_height = LINES;
471    }
472    else
473#endif
474#if defined(USE_CONIO)
475    if(_caca_driver == CACA_DRIVER_CONIO)
476    {
477        gettextinfo(&conio_ti);
478        conio_screen = malloc(2 * conio_ti.screenwidth
479                                 * conio_ti.screenheight * sizeof(char));
480        if(conio_screen == NULL)
481            return -1;
482#   if defined(SCREENUPDATE_IN_PC_H)
483        ScreenRetrieve(conio_screen);
484#   else
485        /* FIXME */
486#   endif
487        _caca_width = conio_ti.screenwidth;
488        _caca_height = conio_ti.screenheight;
489    }
490    else
491#endif
492#if defined(USE_X11)
493    if(_caca_driver == CACA_DRIVER_X11)
494    {
495        static int x11_palette[] =
496        {
497            /* Standard curses colours */
498            0, 0, 0,
499            0, 0, 32768,
500            0, 32768, 0,
501            0, 32768, 32768,
502            32768, 0, 0,
503            32768, 0, 32768,
504            32768, 32768, 0,
505            32768, 32768, 32768,
506            /* Extra values for xterm-16color */
507            16384, 16384, 16384,
508            16384, 16384, 65535,
509            16384, 65535, 16384,
510            16384, 65535, 65535,
511            65535, 16384, 16384,
512            65535, 16384, 65535,
513            65535, 65535, 16384,
514            65535, 65535, 65535,
515        };
516
517        Colormap colormap;
518        const char *font_name = "8x13bold";
519        int i;
520
521        if(getenv("CACA_WIDTH"))
522            _caca_width = atoi(getenv("CACA_WIDTH"));
523        if(!_caca_width)
524            _caca_width = 80;
525
526        if(getenv("CACA_HEIGHT"))
527            _caca_height = atoi(getenv("CACA_HEIGHT"));
528        if(!_caca_height)
529            _caca_height = 32;
530
531        x11_screen = malloc(_caca_width * _caca_height * sizeof(int));
532        if(x11_screen == NULL)
533            return -1;
534
535        x11_dpy = XOpenDisplay(NULL);
536        if(x11_dpy == NULL)
537        {
538            free(x11_screen);
539            return -1;
540        }
541
542        if(getenv("CACA_FONT"))
543            font_name = getenv("CACA_FONT");
544
545        x11_font = XLoadFont(x11_dpy, font_name);
546        if(!x11_font)
547        {
548            XCloseDisplay(x11_dpy);
549            free(x11_screen);
550            return -1;
551        }
552
553        x11_font_struct = XQueryFont(x11_dpy, x11_font);
554        if(!x11_font_struct)
555        {
556            XUnloadFont(x11_dpy, x11_font);
557            XCloseDisplay(x11_dpy);
558            free(x11_screen);
559            return -1;
560        }
561
562        x11_font_width = x11_font_struct->max_bounds.width;
563        x11_font_height = x11_font_struct->max_bounds.ascent
564                             + x11_font_struct->max_bounds.descent;
565        x11_font_offset = x11_font_struct->max_bounds.descent;
566
567        colormap = DefaultColormap(x11_dpy, DefaultScreen(x11_dpy));
568        for(i = 0; i < 16; i++)
569        {
570            XColor color;
571            color.red = x11_palette[i * 3];
572            color.green = x11_palette[i * 3 + 1];
573            color.blue = x11_palette[i * 3 + 2];
574            XAllocColor(x11_dpy, colormap, &color);
575            x11_colors[i] = color.pixel;
576        }
577
578        x11_window = XCreateSimpleWindow(x11_dpy, DefaultRootWindow(x11_dpy),
579                                           0, 0, _caca_width * x11_font_width,
580                                           _caca_height * x11_font_height, 0,
581                                           x11_colors[0], x11_colors[0]);
582        XSelectInput(x11_dpy, x11_window, StructureNotifyMask);
583        XMapWindow(x11_dpy, x11_window);
584
585        x11_gc = XCreateGC(x11_dpy, x11_window, 0, NULL);
586        XSetForeground(x11_dpy, x11_gc, x11_colors[15]);
587        XSetFont(x11_dpy, x11_gc, x11_font);
588
589        for(;;)
590        {
591            XEvent event;
592            XNextEvent(x11_dpy, &event);
593            if (event.type == MapNotify)
594                break;
595        }
596
597        XSelectInput(x11_dpy, x11_window, KeyPressMask);
598
599        XSync(x11_dpy, False);
600
601        x11_pixmap = XCreatePixmap(x11_dpy, x11_window,
602                                   _caca_width * x11_font_width,
603                                   _caca_height * x11_font_height,
604                                   DefaultDepth(x11_dpy,
605                                                DefaultScreen(x11_dpy)));
606    }
607#endif
608
609    _caca_empty_line = malloc(_caca_width + 1);
610    memset(_caca_empty_line, ' ', _caca_width);
611    _caca_empty_line[_caca_width] = '\0';
612
613    _caca_scratch_line = malloc(_caca_width + 1);
614
615    _caca_delay = 0;
616    _caca_rendertime = 0;
617
618    return 0;
619}
620
621int _caca_end_graphics(void)
622{
623#if defined(USE_SLANG)
624    /* Nothing to do */
625#endif
626#if defined(USE_NCURSES)
627    /* Nothing to do */
628#endif
629#if defined(USE_CONIO)
630    if(_caca_driver == CACA_DRIVER_CONIO)
631    {
632        free(conio_screen);
633    }
634    else
635#endif
636#if defined(USE_X11)
637    if(_caca_driver == CACA_DRIVER_X11)
638    {
639        XSync(x11_dpy, False);
640        XFreePixmap(x11_dpy, x11_pixmap);
641        XFreeFont(x11_dpy, x11_font_struct);
642        XFreeGC(x11_dpy, x11_gc);
643        XUnmapWindow(x11_dpy, x11_window);
644        XDestroyWindow(x11_dpy, x11_window);
645        XCloseDisplay(x11_dpy);
646        free(x11_screen);
647    }
648#endif
649    free(_caca_empty_line);
650
651    return 0;
652}
653
654/** \brief Set the refresh delay.
655 *
656 *  This function sets the refresh delay in microseconds. The refresh delay
657 *  is used by caca_refresh() to achieve constant framerate. See the
658 *  caca_refresh() documentation for more details.
659 *
660 *  If the argument is zero, constant framerate is disabled. This is the
661 *  default behaviour.
662 *
663 *  \param usec The refresh delay in microseconds.
664 */
665void caca_set_delay(unsigned int usec)
666{
667    _caca_delay = usec;
668}
669
670/** \brief Get the average rendering time.
671 *
672 *  This function returns the average rendering time, which is the average
673 *  measured time between two caca_refresh() calls, in microseconds. If
674 *  constant framerate was activated by calling caca_set_delay(), the average
675 *  rendering time will not be considerably shorter than the requested delay
676 *  even if the real rendering time was shorter.
677 *
678 *  \return The render time in microseconds.
679 */
680unsigned int caca_get_rendertime(void)
681{
682    return _caca_rendertime;
683}
684
685static unsigned int _caca_getticks(void)
686{
687    static unsigned int last_sec = 0, last_usec = 0;
688
689    struct timeval tv;
690    unsigned int ticks = 0;
691
692    gettimeofday(&tv, NULL);
693
694    if(last_sec != 0)
695    {
696        ticks = (tv.tv_sec - last_sec) * 1000000 + (tv.tv_usec - last_usec);
697    }
698
699    last_sec = tv.tv_sec;
700    last_usec = tv.tv_usec;
701
702    return ticks;
703}
704
705/** \brief Flush pending changes and redraw the screen.
706 *
707 *  This function flushes all graphical operations and prints them to the
708 *  screen. Nothing will show on the screen caca_refresh() is not called.
709 *
710 *  If caca_set_delay() was called with a non-zero value, caca_refresh()
711 *  will use that value to achieve constant framerate: if two consecutive
712 *  calls to caca_refresh() are within a time range shorter than the value
713 *  set with caca_set_delay(), the second call will wait a bit before
714 *  performing the screen refresh.
715 */
716void caca_refresh(void)
717{
718#define IDLE_USEC 10000
719    static int lastticks = 0;
720    int ticks = lastticks + _caca_getticks();
721
722#if defined(USE_SLANG)
723    if(_caca_driver == CACA_DRIVER_SLANG)
724    {
725        SLsmg_refresh();
726    }
727    else
728#endif
729#if defined(USE_NCURSES)
730    if(_caca_driver == CACA_DRIVER_NCURSES)
731    {
732        refresh();
733    }
734    else
735#endif
736#if defined(USE_CONIO)
737    if(_caca_driver == CACA_DRIVER_CONIO)
738    {
739#   if defined(SCREENUPDATE_IN_PC_H)
740        ScreenUpdate(conio_screen);
741#   else
742        /* FIXME */
743#   endif
744    }
745    else
746#endif
747#if defined(USE_X11)
748    if(_caca_driver == CACA_DRIVER_X11)
749    {
750        unsigned int x, y;
751
752        /* FIXME: This is very, very slow. There are several things that can
753         * be done in order to speed up things:
754         *  - cache characters once rendered
755         *  - pre-render all characters
756         *  - use our own rendering routine (screen depth dependent) */
757        for(y = 0; y < _caca_height; y++)
758            for(x = 0; x < _caca_width; x++)
759            {
760                int item = x11_screen[x + y * _caca_width];
761                char data = item >> 8;
762                XSetForeground(x11_dpy, x11_gc, x11_colors[(item >> 4) & 0xf]);
763                XFillRectangle(x11_dpy, x11_pixmap, x11_gc,
764                               x * x11_font_width, y * x11_font_height,
765                               x11_font_width, x11_font_height);
766                XSetForeground(x11_dpy, x11_gc, x11_colors[item & 0xf]);
767                XDrawString(x11_dpy, x11_pixmap, x11_gc, x * x11_font_width,
768                            (y + 1) * x11_font_height - x11_font_offset,
769                            &data, 1);
770            }
771        XCopyArea(x11_dpy, x11_pixmap, x11_window, x11_gc, 0, 0,
772                  _caca_width * x11_font_width, _caca_height * x11_font_height,
773                  0, 0);
774        XFlush(x11_dpy);
775    }
776#endif
777
778    /* Wait until _caca_delay + time of last call */
779    ticks += _caca_getticks();
780    for(; ticks + IDLE_USEC < (int)_caca_delay; ticks += _caca_getticks())
781        usleep(IDLE_USEC);
782
783    /* Update the sliding mean of the render time */
784    _caca_rendertime = (7 * _caca_rendertime + ticks) / 8;
785
786    lastticks = ticks - _caca_delay;
787
788    /* If we drifted too much, it's bad, bad, bad. */
789    if(lastticks > (int)_caca_delay)
790        lastticks = 0;
791}
792
Note: See TracBrowser for help on using the repository browser.