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

Last change on this file since 272 was 272, checked in by Sam Hocevar, 19 years ago
  • src/graphics: + Use XCreateWindow instead of XCreateSimpleWindow. + Set the X window title to "caca for X".
  • Property svn:keywords set to Id
File size: 21.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 graphics.c
23 *  \version \$Id: graphics.c 272 2003-12-24 14:48: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        XSetWindowAttributes x11_attr;
519        const char *font_name = "8x13bold";
520        int i;
521
522        if(getenv("CACA_WIDTH"))
523            _caca_width = atoi(getenv("CACA_WIDTH"));
524        if(!_caca_width)
525            _caca_width = 80;
526
527        if(getenv("CACA_HEIGHT"))
528            _caca_height = atoi(getenv("CACA_HEIGHT"));
529        if(!_caca_height)
530            _caca_height = 32;
531
532        x11_screen = malloc(_caca_width * _caca_height * sizeof(int));
533        if(x11_screen == NULL)
534            return -1;
535
536        x11_dpy = XOpenDisplay(NULL);
537        if(x11_dpy == NULL)
538        {
539            free(x11_screen);
540            return -1;
541        }
542
543        if(getenv("CACA_FONT"))
544            font_name = getenv("CACA_FONT");
545
546        x11_font = XLoadFont(x11_dpy, font_name);
547        if(!x11_font)
548        {
549            XCloseDisplay(x11_dpy);
550            free(x11_screen);
551            return -1;
552        }
553
554        x11_font_struct = XQueryFont(x11_dpy, x11_font);
555        if(!x11_font_struct)
556        {
557            XUnloadFont(x11_dpy, x11_font);
558            XCloseDisplay(x11_dpy);
559            free(x11_screen);
560            return -1;
561        }
562
563        x11_font_width = x11_font_struct->max_bounds.width;
564        x11_font_height = x11_font_struct->max_bounds.ascent
565                             + x11_font_struct->max_bounds.descent;
566        x11_font_offset = x11_font_struct->max_bounds.descent;
567
568        colormap = DefaultColormap(x11_dpy, DefaultScreen(x11_dpy));
569        for(i = 0; i < 16; i++)
570        {
571            XColor color;
572            color.red = x11_palette[i * 3];
573            color.green = x11_palette[i * 3 + 1];
574            color.blue = x11_palette[i * 3 + 2];
575            XAllocColor(x11_dpy, colormap, &color);
576            x11_colors[i] = color.pixel;
577        }
578
579        x11_attr.backing_store = Always;
580        x11_attr.background_pixel = x11_colors[0];
581        x11_attr.event_mask = ExposureMask | StructureNotifyMask;
582
583        x11_window = XCreateWindow(x11_dpy, DefaultRootWindow(x11_dpy), 0, 0,
584                                   _caca_width * x11_font_width,
585                                   _caca_height * x11_font_height,
586                                   0, 0, InputOutput, 0,
587                                   CWBackingStore | CWBackPixel | CWEventMask,
588                                   &x11_attr);
589
590        XStoreName(x11_dpy, x11_window, "caca for X");
591
592        XSelectInput(x11_dpy, x11_window, StructureNotifyMask);
593        XMapWindow(x11_dpy, x11_window);
594
595        x11_gc = XCreateGC(x11_dpy, x11_window, 0, NULL);
596        XSetForeground(x11_dpy, x11_gc, x11_colors[15]);
597        XSetFont(x11_dpy, x11_gc, x11_font);
598
599        for(;;)
600        {
601            XEvent event;
602            XNextEvent(x11_dpy, &event);
603            if (event.type == MapNotify)
604                break;
605        }
606
607        XSelectInput(x11_dpy, x11_window, KeyPressMask);
608
609        XSync(x11_dpy, False);
610
611        x11_pixmap = XCreatePixmap(x11_dpy, x11_window,
612                                   _caca_width * x11_font_width,
613                                   _caca_height * x11_font_height,
614                                   DefaultDepth(x11_dpy,
615                                                DefaultScreen(x11_dpy)));
616    }
617#endif
618
619    _caca_empty_line = malloc(_caca_width + 1);
620    memset(_caca_empty_line, ' ', _caca_width);
621    _caca_empty_line[_caca_width] = '\0';
622
623    _caca_scratch_line = malloc(_caca_width + 1);
624
625    _caca_delay = 0;
626    _caca_rendertime = 0;
627
628    return 0;
629}
630
631int _caca_end_graphics(void)
632{
633#if defined(USE_SLANG)
634    /* Nothing to do */
635#endif
636#if defined(USE_NCURSES)
637    /* Nothing to do */
638#endif
639#if defined(USE_CONIO)
640    if(_caca_driver == CACA_DRIVER_CONIO)
641    {
642        free(conio_screen);
643    }
644    else
645#endif
646#if defined(USE_X11)
647    if(_caca_driver == CACA_DRIVER_X11)
648    {
649        XSync(x11_dpy, False);
650        XFreePixmap(x11_dpy, x11_pixmap);
651        XFreeFont(x11_dpy, x11_font_struct);
652        XFreeGC(x11_dpy, x11_gc);
653        XUnmapWindow(x11_dpy, x11_window);
654        XDestroyWindow(x11_dpy, x11_window);
655        XCloseDisplay(x11_dpy);
656        free(x11_screen);
657    }
658#endif
659    free(_caca_empty_line);
660
661    return 0;
662}
663
664/** \brief Set the refresh delay.
665 *
666 *  This function sets the refresh delay in microseconds. The refresh delay
667 *  is used by caca_refresh() to achieve constant framerate. See the
668 *  caca_refresh() documentation for more details.
669 *
670 *  If the argument is zero, constant framerate is disabled. This is the
671 *  default behaviour.
672 *
673 *  \param usec The refresh delay in microseconds.
674 */
675void caca_set_delay(unsigned int usec)
676{
677    _caca_delay = usec;
678}
679
680/** \brief Get the average rendering time.
681 *
682 *  This function returns the average rendering time, which is the average
683 *  measured time between two caca_refresh() calls, in microseconds. If
684 *  constant framerate was activated by calling caca_set_delay(), the average
685 *  rendering time will not be considerably shorter than the requested delay
686 *  even if the real rendering time was shorter.
687 *
688 *  \return The render time in microseconds.
689 */
690unsigned int caca_get_rendertime(void)
691{
692    return _caca_rendertime;
693}
694
695static unsigned int _caca_getticks(void)
696{
697    static unsigned int last_sec = 0, last_usec = 0;
698
699    struct timeval tv;
700    unsigned int ticks = 0;
701
702    gettimeofday(&tv, NULL);
703
704    if(last_sec != 0)
705    {
706        ticks = (tv.tv_sec - last_sec) * 1000000 + (tv.tv_usec - last_usec);
707    }
708
709    last_sec = tv.tv_sec;
710    last_usec = tv.tv_usec;
711
712    return ticks;
713}
714
715/** \brief Flush pending changes and redraw the screen.
716 *
717 *  This function flushes all graphical operations and prints them to the
718 *  screen. Nothing will show on the screen caca_refresh() is not called.
719 *
720 *  If caca_set_delay() was called with a non-zero value, caca_refresh()
721 *  will use that value to achieve constant framerate: if two consecutive
722 *  calls to caca_refresh() are within a time range shorter than the value
723 *  set with caca_set_delay(), the second call will wait a bit before
724 *  performing the screen refresh.
725 */
726void caca_refresh(void)
727{
728#define IDLE_USEC 10000
729    static int lastticks = 0;
730    int ticks = lastticks + _caca_getticks();
731
732#if defined(USE_SLANG)
733    if(_caca_driver == CACA_DRIVER_SLANG)
734    {
735        SLsmg_refresh();
736    }
737    else
738#endif
739#if defined(USE_NCURSES)
740    if(_caca_driver == CACA_DRIVER_NCURSES)
741    {
742        refresh();
743    }
744    else
745#endif
746#if defined(USE_CONIO)
747    if(_caca_driver == CACA_DRIVER_CONIO)
748    {
749#   if defined(SCREENUPDATE_IN_PC_H)
750        ScreenUpdate(conio_screen);
751#   else
752        /* FIXME */
753#   endif
754    }
755    else
756#endif
757#if defined(USE_X11)
758    if(_caca_driver == CACA_DRIVER_X11)
759    {
760        unsigned int x, y;
761
762        /* FIXME: This is very, very slow. There are several things that can
763         * be done in order to speed up things:
764         *  - cache characters once rendered
765         *  - pre-render all characters
766         *  - use our own rendering routine (screen depth dependent) */
767        for(y = 0; y < _caca_height; y++)
768            for(x = 0; x < _caca_width; x++)
769            {
770                int item = x11_screen[x + y * _caca_width];
771                char data = item >> 8;
772                XSetForeground(x11_dpy, x11_gc, x11_colors[(item >> 4) & 0xf]);
773                XFillRectangle(x11_dpy, x11_pixmap, x11_gc,
774                               x * x11_font_width, y * x11_font_height,
775                               x11_font_width, x11_font_height);
776                XSetForeground(x11_dpy, x11_gc, x11_colors[item & 0xf]);
777                XDrawString(x11_dpy, x11_pixmap, x11_gc, x * x11_font_width,
778                            (y + 1) * x11_font_height - x11_font_offset,
779                            &data, 1);
780            }
781        XCopyArea(x11_dpy, x11_pixmap, x11_window, x11_gc, 0, 0,
782                  _caca_width * x11_font_width, _caca_height * x11_font_height,
783                  0, 0);
784        XFlush(x11_dpy);
785    }
786#endif
787
788    /* Wait until _caca_delay + time of last call */
789    ticks += _caca_getticks();
790    for(; ticks + IDLE_USEC < (int)_caca_delay; ticks += _caca_getticks())
791        usleep(IDLE_USEC);
792
793    /* Update the sliding mean of the render time */
794    _caca_rendertime = (7 * _caca_rendertime + ticks) / 8;
795
796    lastticks = ticks - _caca_delay;
797
798    /* If we drifted too much, it's bad, bad, bad. */
799    if(lastticks > (int)_caca_delay)
800        lastticks = 0;
801}
802
Note: See TracBrowser for help on using the repository browser.