Пример #1
0
/** \brief Print a string.
 *
 *  Print an UTF-8 string at the given coordinates, using the default
 *  foreground and background values. The coordinates may be outside the
 *  canvas boundaries (eg. a negative Y coordinate) and the string will
 *  be cropped accordingly if it is too long.
 *
 *  See caca_put_char() for more information on how fullwidth characters
 *  are handled when overwriting each other or at the canvas' boundaries.
 *
 *  This function returns the number of cells printed by the string. It is
 *  not the number of characters printed, because fullwidth characters
 *  account for two cells.
 *
 *  This function never fails.
 *
 *  \param cv A handle to the libcaca canvas.
 *  \param x X coordinate.
 *  \param y Y coordinate.
 *  \param s The string to print.
 *  \return The number of cells printed.
 */
int caca_put_str(caca_canvas_t *cv, int x, int y, char const *s)
{
    size_t rd;
    int len = 0;

    if (y < 0 || y >= (int)cv->height || x >= (int)cv->width)
    {
        while (*s)
        {
            len += caca_utf32_is_fullwidth(caca_utf8_to_utf32(s, &rd)) ? 2 : 1;
            s += rd ? rd : 1;
        }
        return len;
    }

    while (*s)
    {
        uint32_t ch = caca_utf8_to_utf32(s, &rd);

        if (x + len >= -1 && x + len < (int)cv->width)
            caca_put_char(cv, x + len, y, ch);

        len += caca_utf32_is_fullwidth(ch) ? 2 : 1;
        s += rd ? rd : 1;
    }

    return len;
}
Пример #2
0
static int ncurses_get_event(caca_display_t *dp, caca_privevent_t *ev)
{
    int intkey;

    intkey = getch();
    if(intkey == ERR)
    {
        ev->type = CACA_EVENT_NONE;
        return 0;
    }

    if(intkey < 0x7f)
    {
        ev->type = CACA_EVENT_KEY_PRESS;
        ev->data.key.ch = intkey;
        ev->data.key.utf32 = intkey;
        ev->data.key.utf8[0] = intkey;
        ev->data.key.utf8[1] = '\0';
        return 1;
    }

    /* If the key was UTF-8, parse the whole sequence */
    if(intkey >= 0x80 && intkey < 0x100)
    {
        int keys[7]; /* Necessary for ungetch(); */
        char utf8[7];
        uint32_t utf32;
        size_t i, bytes = 0;

        keys[0] = intkey;
        utf8[0] = intkey;

        for(i = 1; i < 6; i++)
        {
            keys[i] = getch();
            utf8[i] = (unsigned char)keys[i];
        }

        utf8[i] = '\0';
        utf32 = caca_utf8_to_utf32(utf8, &bytes);

        while(i > bytes)
            ungetch(keys[--i]);

        if(bytes)
        {
            ev->type = CACA_EVENT_KEY_PRESS;
            ev->data.key.ch = 0;
            ev->data.key.utf32 = utf32;
            strcpy(ev->data.key.utf8, utf8);
            return 1;
        }
    }

    if(intkey == KEY_MOUSE)
    {
        MEVENT mevent;
        getmouse(&mevent);

        switch(mevent.bstate)
        {
#define PRESS(x) ev->data.mouse.button = x; \
                 ev->type = CACA_EVENT_MOUSE_PRESS; _push_event(dp, ev)
#define RELEASE(x) ev->data.mouse.button = x; \
                   ev->type = CACA_EVENT_MOUSE_RELEASE; _push_event(dp, ev)
#define CLICK(x) PRESS(x); RELEASE(x)
            case BUTTON1_PRESSED: PRESS(1); break;
            case BUTTON1_RELEASED: RELEASE(1); break;
            case BUTTON1_CLICKED: CLICK(1); break;
            case BUTTON1_DOUBLE_CLICKED: CLICK(1); CLICK(1); break;
            case BUTTON1_TRIPLE_CLICKED: CLICK(1); CLICK(1); CLICK(1); break;
            case BUTTON1_RESERVED_EVENT: break;

            case BUTTON2_PRESSED: PRESS(2); break;
            case BUTTON2_RELEASED: RELEASE(2); break;
            case BUTTON2_CLICKED: CLICK(2); break;
            case BUTTON2_DOUBLE_CLICKED: CLICK(2); CLICK(2); break;
            case BUTTON2_TRIPLE_CLICKED: CLICK(2); CLICK(2); CLICK(2); break;
            case BUTTON2_RESERVED_EVENT: break;

            case BUTTON3_PRESSED: PRESS(3); break;
            case BUTTON3_RELEASED: RELEASE(3); break;
            case BUTTON3_CLICKED: CLICK(3); break;
            case BUTTON3_DOUBLE_CLICKED: CLICK(3); CLICK(3); break;
            case BUTTON3_TRIPLE_CLICKED: CLICK(3); CLICK(3); CLICK(3); break;
            case BUTTON3_RESERVED_EVENT: break;

            case BUTTON4_PRESSED: PRESS(4); break;
            case BUTTON4_RELEASED: RELEASE(4); break;
            case BUTTON4_CLICKED: CLICK(4); break;
            case BUTTON4_DOUBLE_CLICKED: CLICK(4); CLICK(4); break;
            case BUTTON4_TRIPLE_CLICKED: CLICK(4); CLICK(4); CLICK(4); break;
            case BUTTON4_RESERVED_EVENT: break;

            default:
                break;
#undef PRESS
#undef RELEASE
#undef CLICK
        }

        if(dp->mouse.x == mevent.x && dp->mouse.y == mevent.y)
            return _pop_event(dp, ev);

        dp->mouse.x = mevent.x;
        dp->mouse.y = mevent.y;

        ev->type = CACA_EVENT_MOUSE_MOTION;
        ev->data.mouse.x = dp->mouse.x;
        ev->data.mouse.y = dp->mouse.y;
        return 1;
    }

    switch(intkey)
    {
        case KEY_UP: ev->data.key.ch = CACA_KEY_UP; break;
        case KEY_DOWN: ev->data.key.ch = CACA_KEY_DOWN; break;
        case KEY_LEFT: ev->data.key.ch = CACA_KEY_LEFT; break;
        case KEY_RIGHT: ev->data.key.ch = CACA_KEY_RIGHT; break;

        case KEY_IC: ev->data.key.ch = CACA_KEY_INSERT; break;
        case KEY_DC: ev->data.key.ch = CACA_KEY_DELETE; break;
        case 0x7f:
        case KEY_BACKSPACE: ev->data.key.ch = CACA_KEY_BACKSPACE; break;
        case KEY_HOME: ev->data.key.ch = CACA_KEY_HOME; break;
        case KEY_END: ev->data.key.ch = CACA_KEY_END; break;
        case KEY_PPAGE: ev->data.key.ch = CACA_KEY_PAGEUP; break;
        case KEY_NPAGE: ev->data.key.ch = CACA_KEY_PAGEDOWN; break;

        case KEY_F(1): ev->data.key.ch = CACA_KEY_F1; break;
        case KEY_F(2): ev->data.key.ch = CACA_KEY_F2; break;
        case KEY_F(3): ev->data.key.ch = CACA_KEY_F3; break;
        case KEY_F(4): ev->data.key.ch = CACA_KEY_F4; break;
        case KEY_F(5): ev->data.key.ch = CACA_KEY_F5; break;
        case KEY_F(6): ev->data.key.ch = CACA_KEY_F6; break;
        case KEY_F(7): ev->data.key.ch = CACA_KEY_F7; break;
        case KEY_F(8): ev->data.key.ch = CACA_KEY_F8; break;
        case KEY_F(9): ev->data.key.ch = CACA_KEY_F9; break;
        case KEY_F(10): ev->data.key.ch = CACA_KEY_F10; break;
        case KEY_F(11): ev->data.key.ch = CACA_KEY_F11; break;
        case KEY_F(12): ev->data.key.ch = CACA_KEY_F12; break;

        default:
            /* Unknown key */
            ev->type = CACA_EVENT_NONE; return 0;
    }

    ev->type = CACA_EVENT_KEY_PRESS;
    ev->data.key.utf32 = 0;
    ev->data.key.utf8[0] = '\0';
    return 1;
}
Пример #3
0
static caca_charfont_t * open_charfont(char const *path)
{
    char buf[2048];
    char hardblank[10];
    caca_charfont_t *ff;
    char *data = NULL;
    caca_file_t *f;
#if !defined __KERNEL__ && (defined HAVE_SNPRINTF || defined HAVE_SPRINTF_S)
    int const pathlen = 2048;
    char *altpath = NULL;
#endif
    int i, j, size, comment_lines;

    ff = malloc(sizeof(caca_charfont_t));
    if(!ff)
    {
        seterrno(ENOMEM);
        return NULL;
    }

    /* Open font: if not found, try .tlf, then .flf */
    f = caca_file_open(path, "r");
#if !defined __KERNEL__ && (defined HAVE_SNPRINTF || defined HAVE_SPRINTF_S)
    if(!f)
        altpath = malloc(pathlen);
    if(!f)
    {
#if defined HAVE_SPRINTF_S
        sprintf_s(altpath, pathlen - 1, "%s.tlf", path);
#else
        snprintf(altpath, pathlen - 1, "%s.tlf", path);
#endif
        altpath[pathlen - 1] = '\0';
        f = caca_file_open(altpath, "r");
    }
    if(!f)
    {
#if defined HAVE_SPRINTF_S
        sprintf_s(altpath, pathlen - 1, "%s.flf", path);
#else
        snprintf(altpath, pathlen - 1, "%s.flf", path);
#endif
        altpath[pathlen - 1] = '\0';
        f = caca_file_open(altpath, "r");
    }
    if (altpath)
        free(altpath);
#endif
    if(!f)
    {
        free(ff);
        seterrno(ENOENT);
        return NULL;
    }

    /* Read header */
    ff->print_direction = 0;
    ff->full_layout = 0;
    ff->codetag_count = 0;
    caca_file_gets(f, buf, 2048);
    if(sscanf(buf, "%*[ft]lf2a%6s %u %u %u %i %u %u %u %u\n", hardblank,
              &ff->height, &ff->baseline, &ff->max_length,
              &ff->old_layout, &comment_lines, &ff->print_direction,
              &ff->full_layout, &ff->codetag_count) < 6)
    {
        debug("figfont error: `%s' has invalid header: %s", path, buf);
        caca_file_close(f);
        free(ff);
        seterrno(EINVAL);
        return NULL;
    }

    if(ff->old_layout < -1 || ff->old_layout > 63 || ff->full_layout > 32767
        || ((ff->full_layout & 0x80) && (ff->full_layout & 0x3f) == 0
            && ff->old_layout))
    {
        debug("figfont error: `%s' has invalid layout %i/%u",
                path, ff->old_layout, ff->full_layout);
        caca_file_close(f);
        free(ff);
        seterrno(EINVAL);
        return NULL;
    }

    ff->hardblank = caca_utf8_to_utf32(hardblank, NULL);

    /* Skip comment lines */
    for(i = 0; i < comment_lines; i++)
        caca_file_gets(f, buf, 2048);

    /* Read mandatory characters (32-127, 196, 214, 220, 228, 246, 252, 223)
     * then read additional characters. */
    ff->glyphs = 0;
    ff->lookup = NULL;

    for(i = 0, size = 0; !caca_file_eof(f); ff->glyphs++)
    {
        if((ff->glyphs % 2048) == 0)
            ff->lookup = realloc(ff->lookup,
                                   (ff->glyphs + 2048) * 2 * sizeof(int));

        if(ff->glyphs < STD_GLYPHS)
        {
            ff->lookup[ff->glyphs * 2] = 32 + ff->glyphs;
        }
        else if(ff->glyphs < EXT_GLYPHS)
        {
            static int const tab[7] = { 196, 214, 220, 228, 246, 252, 223 };
            ff->lookup[ff->glyphs * 2] = tab[ff->glyphs - STD_GLYPHS];
        }
        else
        {
            unsigned int tmp;

            if(caca_file_gets(f, buf, 2048) == NULL)
                break;

            /* Ignore blank lines, as in jacky.flf */
            if(buf[0] == '\n' || buf[0] == '\r')
                continue;

            /* Ignore negative indices for now, as in ivrit.flf */
            if(buf[0] == '-')
            {
                for(j = 0; j < ff->height; j++)
                    caca_file_gets(f, buf, 2048);
                continue;
            }

            if(!buf[0] || buf[0] < '0' || buf[0] > '9')
            {
                debug("figfont error: glyph #%u in `%s'", ff->glyphs, path);
                free(data);
                free(ff->lookup);
                free(ff);
                seterrno(EINVAL);
                return NULL;
            }

            sscanf(buf, buf[1] == 'x' ? "%x" : "%u", &tmp);
            ff->lookup[ff->glyphs * 2] = tmp;
        }

        ff->lookup[ff->glyphs * 2 + 1] = 0;

        for(j = 0; j < ff->height; j++)
        {
            if(i + 2048 >= size)
                data = realloc(data, size += 2048);

            caca_file_gets(f, data + i, 2048);
            i = (uintptr_t)strchr(data + i, 0) - (uintptr_t)data;
        }
    }

    caca_file_close(f);

    if(ff->glyphs < EXT_GLYPHS)
    {
        debug("figfont error: only %u glyphs in `%s', expected at least %u",
                        ff->glyphs, path, EXT_GLYPHS);
        free(data);
        free(ff->lookup);
        free(ff);
        seterrno(EINVAL);
        return NULL;
    }

    /* Remaining initialisation */
    ff->charcv = NULL;
    ff->left = NULL;
    ff->right = NULL;

    /* Import buffer into canvas */
    ff->fontcv = caca_create_canvas(0, 0);
    caca_import_canvas_from_memory(ff->fontcv, data, i, "utf8");
    free(data);

    /* Remove EOL characters. For now we ignore hardblanks, don’t do any
     * smushing, nor any kind of error checking. */
    for(j = 0; j < ff->height * ff->glyphs; j++)
    {
        uint32_t ch, oldch = 0;

        for(i = ff->max_length; i--;)
        {
            ch = caca_get_char(ff->fontcv, i, j);

            /* Replace hardblanks with U+00A0 NO-BREAK SPACE */
            if(ch == ff->hardblank)
                caca_put_char(ff->fontcv, i, j, ch = 0xa0);

            if(oldch && ch != oldch)
            {
                if(!ff->lookup[j / ff->height * 2 + 1])
                    ff->lookup[j / ff->height * 2 + 1] = i + 1;
            }
            else if(oldch && ch == oldch)
                caca_put_char(ff->fontcv, i, j, ' ');
            else if(ch != ' ')
            {
                oldch = ch;
                caca_put_char(ff->fontcv, i, j, ' ');
            }
        }
    }

    return ff;
}
Пример #4
0
static int slang_get_event(caca_display_t *dp, caca_privevent_t *ev)
{
    int intkey;

    /* If SIGINT was caught, we pass it to the application as Ctrl-C. */
    if(dp->drv.p->sigint_event > 0)
    {
        ev->type = CACA_EVENT_KEY_PRESS;
        ev->data.key.ch = CACA_KEY_CTRL_C;
        ev->data.key.utf32 = 0x03;
        ev->data.key.utf8[0] = 0x03;
        ev->data.key.utf8[1] = 0;
        dp->drv.p->sigint_event--;
        return 1;
    }

    if(!SLang_input_pending(0))
    {
        ev->type = CACA_EVENT_NONE;
        return 0;
    }

    /* We first use SLang_getkey() to see whether Esc was pressed
     * alone, then (if it wasn't) we unget the key and use SLkp_getkey()
     * instead, so that escape sequences are interpreted. */
    intkey = SLang_getkey();

    if(intkey != 0x1b /* Esc */ || SLang_input_pending(0))
    {
        SLang_ungetkey(intkey);
        intkey = SLkp_getkey();
    }

    /* If the key was ASCII, return it immediately */
    if(intkey < 0x7f)
    {
        ev->type = CACA_EVENT_KEY_PRESS;
        ev->data.key.ch = intkey;
        ev->data.key.utf32 = intkey;
        ev->data.key.utf8[0] = intkey;
        ev->data.key.utf8[1] = '\0';
        return 1;
    }

    /* If the key was UTF-8, parse the whole sequence */
    if(intkey >= 0x80 && intkey < 0x100)
    {
        int keys[7]; /* Necessary for ungetkey(); */
        char utf8[7];
        uint32_t utf32;
        size_t i, bytes = 0;

        keys[0] = intkey;
        utf8[0] = intkey;

        for(i = 1; i < 6; i++)
        {
            if(!SLang_input_pending(0))
                break;
            keys[i] = SLang_getkey();
            utf8[i] = (unsigned char)keys[i];
        }

        utf8[i] = '\0';
        utf32 = caca_utf8_to_utf32(utf8, &bytes);

        while(i > bytes)
            SLang_ungetkey(keys[--i]);

        if(bytes)
        {
            ev->type = CACA_EVENT_KEY_PRESS;
            ev->data.key.ch = 0;
            ev->data.key.utf32 = utf32;
            strcpy(ev->data.key.utf8, utf8);
            return 1;
        }
    }

    if(intkey == 0x3e9)
    {
        int button = (SLang_getkey() - ' ' + 1) & 0xf;
        int x = SLang_getkey() - '!';
        int y = SLang_getkey() - '!';

        ev->data.mouse.button = button;
        ev->type = CACA_EVENT_MOUSE_PRESS;
        _push_event(dp, ev);
        ev->type = CACA_EVENT_MOUSE_RELEASE;
        _push_event(dp, ev);

        if(dp->mouse.x == x && dp->mouse.y == y)
            return _pop_event(dp, ev);

        dp->mouse.x = x;
        dp->mouse.y = y;

        ev->type = CACA_EVENT_MOUSE_MOTION;
        ev->data.mouse.x = dp->mouse.x;
        ev->data.mouse.y = dp->mouse.y;
        return 1;
    }

    switch(intkey)
    {
        case SL_KEY_UP: ev->data.key.ch = CACA_KEY_UP; break;
        case SL_KEY_DOWN: ev->data.key.ch = CACA_KEY_DOWN; break;
        case SL_KEY_LEFT: ev->data.key.ch = CACA_KEY_LEFT; break;
        case SL_KEY_RIGHT: ev->data.key.ch = CACA_KEY_RIGHT; break;

        case SL_KEY_IC: ev->data.key.ch = CACA_KEY_INSERT; break;
        case SL_KEY_DELETE: ev->data.key.ch = CACA_KEY_DELETE; break;
        case 0x7f:
        case SL_KEY_BACKSPACE: ev->data.key.ch = CACA_KEY_BACKSPACE; break;
        case SL_KEY_HOME: ev->data.key.ch = CACA_KEY_HOME; break;
        case SL_KEY_END: ev->data.key.ch = CACA_KEY_END; break;
        case SL_KEY_PPAGE: ev->data.key.ch = CACA_KEY_PAGEUP; break;
        case SL_KEY_NPAGE: ev->data.key.ch = CACA_KEY_PAGEDOWN; break;

        case SL_KEY_F(1): ev->data.key.ch = CACA_KEY_F1; break;
        case SL_KEY_F(2): ev->data.key.ch = CACA_KEY_F2; break;
        case SL_KEY_F(3): ev->data.key.ch = CACA_KEY_F3; break;
        case SL_KEY_F(4): ev->data.key.ch = CACA_KEY_F4; break;
        case SL_KEY_F(5): ev->data.key.ch = CACA_KEY_F5; break;
        case SL_KEY_F(6): ev->data.key.ch = CACA_KEY_F6; break;
        case SL_KEY_F(7): ev->data.key.ch = CACA_KEY_F7; break;
        case SL_KEY_F(8): ev->data.key.ch = CACA_KEY_F8; break;
        case SL_KEY_F(9): ev->data.key.ch = CACA_KEY_F9; break;
        case SL_KEY_F(10): ev->data.key.ch = CACA_KEY_F10; break;
        case SL_KEY_F(11): ev->data.key.ch = CACA_KEY_F11; break;
        case SL_KEY_F(12): ev->data.key.ch = CACA_KEY_F12; break;

        default:
            /* Unknown key */
            ev->type = CACA_EVENT_NONE; return 0;
    }

    ev->type = CACA_EVENT_KEY_PRESS;
    ev->data.key.utf32 = 0;
    ev->data.key.utf8[0] = '\0';
    return 1;
}
Пример #5
0
int main(int argc, char *argv[])
{
    textentry entries[TEXT_ENTRIES];
    caca_canvas_t *cv;
    caca_display_t *dp;
    unsigned int i, e = 0, running = 1;

    cv = caca_create_canvas(0, 0);
    if(cv == NULL)
    {
        printf("Can't create canvas\n");
        return -1;
    }
    dp = caca_create_display(cv);
    if(dp == NULL)
    {
        printf("Can't create display\n");
        return -1;
    }
    caca_set_cursor(dp, 1);

    caca_set_color_ansi(cv, CACA_WHITE, CACA_BLUE);
    caca_put_str(cv, 1, 1, "Text entries - press tab to cycle");

    for(i = 0; i < TEXT_ENTRIES; i++)
    {
        entries[i].buffer[0] = 0;
        entries[i].size = 0;
        entries[i].cursor = 0;
        entries[i].changed = 1;
        caca_printf(cv, 3, 3 * i + 4, "[entry %i]", i + 1);
    }

    /* Put Unicode crap in the last text entry */
    entries[TEXT_ENTRIES - 1].buffer[0] = 'A';
    entries[TEXT_ENTRIES - 1].buffer[1] = 'b';
    entries[TEXT_ENTRIES - 1].buffer[2] = caca_utf8_to_utf32("Ç", NULL);
    entries[TEXT_ENTRIES - 1].buffer[3] = caca_utf8_to_utf32("đ", NULL);
    entries[TEXT_ENTRIES - 1].buffer[4] = caca_utf8_to_utf32("ボ", NULL);
    entries[TEXT_ENTRIES - 1].buffer[5] = CACA_MAGIC_FULLWIDTH;
    entries[TEXT_ENTRIES - 1].buffer[6] = caca_utf8_to_utf32("♥", NULL);
    entries[TEXT_ENTRIES - 1].size = 7;

    while(running)
    {
        caca_event_t ev;

        for(i = 0; i < TEXT_ENTRIES; i++)
        {
            unsigned int j, start, size;

            if(!entries[i].changed)
                continue;

            caca_set_color_ansi(cv, CACA_BLACK, CACA_LIGHTGRAY);
            caca_fill_box(cv, 2, 3 * i + 5, BUFFER_SIZE + 1, 1, ' ');

            start = 0;
            size = entries[i].size;

            for(j = 0; j < size; j++)
            {
                caca_put_char(cv, 2 + j, 3 * i + 5,
                              entries[i].buffer[start + j]);
            }

            entries[i].changed = 0;
        }

        /* Put the cursor on the active textentry */
        caca_gotoxy(cv, 2 + entries[e].cursor, 3 * e + 5);

        caca_refresh_display(dp);

        if(caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, -1) == 0)
            continue;

        switch(caca_get_event_key_ch(&ev))
        {
            case CACA_KEY_ESCAPE:
                running = 0;
                break;
            case CACA_KEY_TAB:
            case CACA_KEY_RETURN:
                e = (e + 1) % TEXT_ENTRIES;
                break;
            case CACA_KEY_HOME:
                entries[e].cursor = 0;
                break;
            case CACA_KEY_END:
                entries[e].cursor = entries[e].size;
                break;
            case CACA_KEY_LEFT:
                if(entries[e].cursor)
                    entries[e].cursor--;
                break;
            case CACA_KEY_RIGHT:
                if(entries[e].cursor < entries[e].size)
                    entries[e].cursor++;
                break;
            case CACA_KEY_DELETE:
                if(entries[e].cursor < entries[e].size)
                {
                    memmove(entries[e].buffer + entries[e].cursor,
                            entries[e].buffer + entries[e].cursor + 1,
                            (entries[e].size - entries[e].cursor + 1) * 4);
                    entries[e].size--;
                    entries[e].changed = 1;
                }
                break;
            case CACA_KEY_BACKSPACE:
                if(entries[e].cursor)
                {
                    memmove(entries[e].buffer + entries[e].cursor - 1,
                            entries[e].buffer + entries[e].cursor,
                            (entries[e].size - entries[e].cursor) * 4);
                    entries[e].size--;
                    entries[e].cursor--;
                    entries[e].changed = 1;
                }
                break;
            default:
                if(entries[e].size < BUFFER_SIZE)
                {
                    memmove(entries[e].buffer + entries[e].cursor + 1,
                            entries[e].buffer + entries[e].cursor,
                            (entries[e].size - entries[e].cursor) * 4);
                    entries[e].buffer[entries[e].cursor] =
                                              caca_get_event_key_utf32(&ev);
                    entries[e].size++;
                    entries[e].cursor++;
                    entries[e].changed = 1;
                }
                break;
        }
    }

    caca_free_display(dp);
    caca_free_canvas(cv);

    return 0;
}