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

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