Esempio n. 1
0
/** \brief Flip a canvas vertically.
 *
 *  Flip a canvas vertically, choosing characters that look like the
 *  mirrored version wherever possible. Some characters will stay
 *  unchanged by the process, but the operation is guaranteed to be
 *  involutive: performing it again gives back the original canvas.
 *
 *  This function never fails.
 *
 *  \param cv The canvas to flop.
 *  \return This function always returns 0.
 */
int caca_flop(caca_canvas_t *cv)
{
    int x;

    for(x = 0; x < cv->width; x++)
    {
        uint32_t *ctop = cv->chars + x;
        uint32_t *cbottom = ctop + cv->width * (cv->height - 1);
        uint32_t *atop = cv->attrs + x;
        uint32_t *abottom = atop + cv->width * (cv->height - 1);

        while(ctop < cbottom)
        {
            uint32_t ch;
            uint32_t attr;

            /* Swap attributes */
            attr = *abottom; *abottom = *atop; *atop = attr;

            /* Swap characters */
            ch = *cbottom; *cbottom = flopchar(*ctop); *ctop = flopchar(ch);

            ctop += cv->width; cbottom -= cv->width;
            atop += cv->width; abottom -= cv->width;
        }

        if(ctop == cbottom)
            *ctop = flopchar(*ctop);
    }

    if(!cv->dirty_disabled)
        caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);

    return 0;
}
Esempio n. 2
0
static int vga_init_graphics(caca_display_t *dp)
{
    int i;
    uint8_t tmp;

    /* Blank screen */
    memset(VGA_SCREEN, 0, 80 * 25 * 2);

    /* Fill VGA palette */
    for(i = 0; i < 16; i++)
    {
        outb(vga_colors[i][0], 0x3c8);
        outb(vga_colors[i][1], 0x3c9);
        outb(vga_colors[i][2], 0x3c9);
        outb(vga_colors[i][3], 0x3c9);
    }

    /* Hide cursor */
    outb(0x0a, 0x3d4);
    tmp = inb(0x3d5);
    tmp |= 0x20;
    outb(0x0a, 0x3d4);
    outb(tmp, 0x3d5);

    caca_add_dirty_rect(dp->cv, 0, 0, dp->cv->width, dp->cv->height);
    dp->resize.allow = 1;
    caca_set_canvas_size(dp->cv, 80, 25); /* We don't have much choice */
    dp->resize.allow = 0;

    return 0;
}
Esempio n. 3
0
/** \brief Fill a box on the canvas using the given character.
 *
 *  This function never fails.
 *
 *  \param cv The handle to the libcaca canvas.
 *  \param x X coordinate of the upper-left corner of the box.
 *  \param y Y coordinate of the upper-left corner of the box.
 *  \param w Width of the box.
 *  \param h Height of the box.
 *  \param ch UTF-32 character to be used to draw the box.
 *  \return This function always returns 0.
 */
int caca_fill_box(caca_canvas_t *cv, int x, int y, int w, int h,
                   uint32_t ch)
{
    int i, j, xmax, ymax;

    int x2 = x + w - 1;
    int y2 = y + h - 1;

    if(x > x2)
    {
        int tmp = x;
        x = x2; x2 = tmp;
    }

    if(y > y2)
    {
        int tmp = y;
        y = y2; y2 = tmp;
    }

    xmax = cv->width - 1;
    ymax = cv->height - 1;

    if(x2 < 0 || y2 < 0 || x > xmax || y > ymax)
        return 0;

    if(x < 0) x = 0;
    if(y < 0) y = 0;
    if(x2 > xmax) x2 = xmax;
    if(y2 > ymax) y2 = ymax;

#if 0
    /* FIXME: this fails with fullwidth character blits. Also, the dirty
     * rectangle handling may miss fullwidth cells. */
    /* Optimise dirty rectangle handling, part 1 */
    cv->dirty_disabled++;
#endif

    for(j = y; j <= y2; j++)
        for(i = x; i <= x2; i++)
            caca_put_char(cv, i, j, ch);

#if 0
    /* Optimise dirty rectangle handling, part 2 */
    cv->dirty_disabled--;
    if(!cv->dirty_disabled)
        caca_add_dirty_rect(cv, x, y, x2 - x + 1, y2 - y + 1);
#endif

    return 0;
}
Esempio n. 4
0
/** \brief Flip a canvas horizontally.
 *
 *  Flip a canvas horizontally, choosing characters that look like the
 *  mirrored version wherever possible. Some characters will stay
 *  unchanged by the process, but the operation is guaranteed to be
 *  involutive: performing it again gives back the original canvas.
 *
 *  This function never fails.
 *
 *  \param cv The canvas to flip.
 *  \return This function always returns 0.
 */
int caca_flip(caca_canvas_t *cv)
{
    int y;

    for(y = 0; y < cv->height; y++)
    {
        uint32_t *cleft = cv->chars + y * cv->width;
        uint32_t *cright = cleft + cv->width - 1;
        uint32_t *aleft = cv->attrs + y * cv->width;
        uint32_t *aright = aleft + cv->width - 1;

        while(cleft < cright)
        {
            uint32_t ch;
            uint32_t attr;

            /* Swap attributes */
            attr = *aright;
            *aright-- = *aleft;
            *aleft++ = attr;

            /* Swap characters */
            ch = *cright;
            *cright-- = flipchar(*cleft);
            *cleft++ = flipchar(ch);
        }

        if(cleft == cright)
            *cleft = flipchar(*cleft);

        /* Fix fullwidth characters. Could it be done in one loop? */
        cleft = cv->chars + y * cv->width;
        cright = cleft + cv->width - 1;
        for( ; cleft < cright; cleft++)
        {
            if(cleft[0] == CACA_MAGIC_FULLWIDTH)
            {
                cleft[0] = cleft[1];
                cleft[1] = CACA_MAGIC_FULLWIDTH;
                cleft++;
            }
        }
    }

    if(!cv->dirty_disabled)
        caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);

    return 0;
}
Esempio n. 5
0
/** \brief Rotate a canvas.
 *
 *  Apply a 180-degree transformation to a canvas, choosing characters
 *  that look like the upside-down version wherever possible. Some
 *  characters will stay unchanged by the process, but the operation is
 *  guaranteed to be involutive: performing it again gives back the
 *  original canvas.
 *
 *  This function never fails.
 *
 *  \param cv The canvas to rotate.
 *  \return This function always returns 0.
 */
int caca_rotate_180(caca_canvas_t *cv)
{
    uint32_t *cbegin = cv->chars;
    uint32_t *cend = cbegin + cv->width * cv->height - 1;
    uint32_t *abegin = cv->attrs;
    uint32_t *aend = abegin + cv->width * cv->height - 1;
    int y;

    if(!cbegin)
      return 0;

    while(cbegin < cend)
    {
        uint32_t ch;
        uint32_t attr;

        /* Swap attributes */
        attr = *aend; *aend = *abegin; *abegin = attr;

        /* Swap characters */
        ch = *cend; *cend = rotatechar(*cbegin); *cbegin = rotatechar(ch);

        cbegin++; cend--; abegin++; aend--;
    }

    if(cbegin == cend)
        *cbegin = rotatechar(*cbegin);

    /* Fix fullwidth characters. Could it be done in one loop? */
    for(y = 0; y < cv->height; y++)
    {
        cbegin = cv->chars + y * cv->width;
        cend = cbegin + cv->width - 1;
        for( ; cbegin < cend; cbegin++)
        {
            if(cbegin[0] == CACA_MAGIC_FULLWIDTH)
            {
                cbegin[0] = cbegin[1];
                cbegin[1] = CACA_MAGIC_FULLWIDTH;
                cbegin++;
            }
        }
    }

    if(!cv->dirty_disabled)
        caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);

    return 0;
}
Esempio n. 6
0
/** \brief Clear the canvas.
 *
 *  Clear the canvas using the current foreground and background colours.
 *
 *  This function never fails.
 *
 *  \param cv The canvas to clear.
 *  \return This function always returns 0.
 */
int caca_clear_canvas(caca_canvas_t *cv)
{
    uint32_t attr = cv->curattr;
    int n;

    for(n = cv->width * cv->height; n--; )
    {
        cv->chars[n] = (uint32_t)' ';
        cv->attrs[n] = attr;
    }

    if(!cv->dirty_disabled)
        caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);

    return 0;
}
Esempio n. 7
0
/** \brief Invert a canvas' colours.
 *
 *  Invert a canvas' colours (black becomes white, red becomes cyan, etc.)
 *  without changing the characters in it.
 *
 *  This function never fails.
 *
 *  \param cv The canvas to invert.
 *  \return This function always returns 0.
 */
int caca_invert(caca_canvas_t *cv)
{
    uint32_t *attrs = cv->attrs;
    int i;

    for(i = cv->height * cv->width; i--; )
    {
        *attrs = *attrs ^ 0x000f000f;
        attrs++;
    }

    if(!cv->dirty_disabled)
        caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);

    return 0;
}
Esempio n. 8
0
/** \brief Activate a given canvas frame.
 *
 *  Set the active canvas frame. All subsequent drawing operations will
 *  be performed on that frame. The current painting context set by
 *  caca_set_attr() is inherited.
 *
 *  If the frame index is outside the canvas' frame range, nothing happens.
 *
 *  If an error occurs, -1 is returned and \b errno is set accordingly:
 *  - \c EINVAL Requested frame is out of range.
 *
 *  \param cv A libcaca canvas
 *  \param id The canvas frame to activate
 *  \return 0 in case of success, -1 if an error occurred.
 */
int caca_set_frame(caca_canvas_t *cv, int id)
{
    if(id < 0 || id >= cv->framecount)
    {
        seterrno(EINVAL);
        return -1;
    }

    /* Bail out if no operation is required */
    if(id == cv->frame)
        return 0;

    _caca_save_frame_info(cv);
    cv->frame = id;
    _caca_load_frame_info(cv);

    if(!cv->dirty_disabled)
        caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);

    return 0;
}
Esempio n. 9
0
/** \brief Remove a frame from a canvas.
 *
 *  Delete a frame from a given canvas.
 *
 *  The frame index indicates the frame to delete. Valid values range from
 *  0 to the current canvas frame count minus 1. If the frame index is
 *  greater than or equals the current canvas frame count, the last frame
 *  is deleted.
 *
 *  If the active frame is deleted, frame 0 becomes the new active frame.
 *  Otherwise, the active frame does not change, but its index may be
 *  renumbered due to the deletion.
 *
 *  If an error occurs, -1 is returned and \b errno is set accordingly:
 *  - \c EINVAL Requested frame is out of range, or attempt to delete the
 *    last frame of the canvas.
 *
 *  \param cv A libcaca canvas
 *  \param id The index of the frame to delete
 *  \return 0 in case of success, -1 if an error occurred.
 */
int caca_free_frame(caca_canvas_t *cv, int id)
{
    int f;

    if(id < 0 || id >= cv->framecount)
    {
        seterrno(EINVAL);
        return -1;
    }

    if(cv->framecount == 1)
    {
        seterrno(EINVAL);
        return -1;
    }

    free(cv->frames[id].chars);
    free(cv->frames[id].attrs);
    free(cv->frames[id].name);

    for(f = id + 1; f < cv->framecount; f++)
        cv->frames[f - 1] = cv->frames[f];

    cv->framecount--;
    cv->frames = realloc(cv->frames,
                         sizeof(struct caca_frame) * cv->framecount);

    if(cv->frame > id)
        cv->frame--;
    else if(cv->frame == id)
    {
        cv->frame = 0;
        _caca_load_frame_info(cv);
        if(!cv->dirty_disabled)
            caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
    }

    return 0;
}
Esempio n. 10
0
/** \brief Blit a canvas onto another one.
 *
 *  Blit a canvas onto another one at the given coordinates.
 *  An optional mask canvas can be used.
 *
 *  If an error occurs, -1 is returned and \b errno is set accordingly:
 *  - \c EINVAL A mask was specified but the mask size and source canvas
 *    size do not match.
 *
 *  \param dst The destination canvas.
 *  \param x X coordinate.
 *  \param y Y coordinate.
 *  \param src The source canvas.
 *  \param mask The mask canvas.
 *  \return 0 in case of success, -1 if an error occurred.
 */
int caca_blit(caca_canvas_t *dst, int x, int y,
              caca_canvas_t const *src, caca_canvas_t const *mask)
{
    int i, j, starti, startj, endi, endj, stride, bleed_left, bleed_right;

    if(mask && (src->width != mask->width || src->height != mask->height))
    {
        seterrno(EINVAL);
        return -1;
    }

    x -= src->frames[src->frame].handlex;
    y -= src->frames[src->frame].handley;

    starti = x < 0 ? -x : 0;
    startj = y < 0 ? -y : 0;
    endi = (x + src->width >= dst->width) ? dst->width - x : src->width;
    endj = (y + src->height >= dst->height) ? dst->height - y : src->height;
    stride = endi - starti;

    if(starti > src->width || startj > src->height
        || starti >= endi || startj >= endj)
        return 0;

    bleed_left = bleed_right = 0;

    for(j = startj; j < endj; j++)
    {
        int dstix = (j + y) * dst->width + starti + x;
        int srcix = j * src->width + starti;

        /* FIXME: we are ignoring the mask here */
        if((starti + x) && dst->chars[dstix] == CACA_MAGIC_FULLWIDTH)
        {
            dst->chars[dstix - 1] = ' ';
            bleed_left = 1;
        }

        if(endi + x < dst->width
                && dst->chars[dstix + stride] == CACA_MAGIC_FULLWIDTH)
        {
            dst->chars[dstix + stride] = ' ';
            bleed_right = 1;
        }

        if(mask)
        {
            for(i = 0; i < stride; i++)
            {
                if(mask->chars[srcix + i] == (uint32_t)' ')
                    continue;

                if(dst->chars[dstix + i] != src->chars[srcix + i] ||
                   dst->attrs[dstix + i] != src->attrs[srcix + i])
                {
                    dst->chars[dstix + i] = src->chars[srcix + i];
                    dst->attrs[dstix + i] = src->attrs[srcix + i];
                    if(!dst->dirty_disabled)
                        caca_add_dirty_rect(dst, x + starti + i, y + j, 1, 1);
                }
            }
        }
        else
        {
            if(memcmp(dst->chars + dstix, src->chars + srcix, stride * 4) ||
               memcmp(dst->attrs + dstix, src->attrs + srcix, stride * 4))
            {
                /* FIXME be more precise ? */
                memcpy(dst->chars + dstix, src->chars + srcix, stride * 4);
                memcpy(dst->attrs + dstix, src->attrs + srcix, stride * 4);
                if(!dst->dirty_disabled)
                    caca_add_dirty_rect(dst, x + starti, y + j, stride, 1);
            }
        }

        /* Fix split fullwidth chars */
        if(src->chars[srcix] == CACA_MAGIC_FULLWIDTH)
            dst->chars[dstix] = ' ';

        if(endi < src->width && src->chars[endi] == CACA_MAGIC_FULLWIDTH)
            dst->chars[dstix + stride - 1] = ' ';
    }


    return 0;
}
Esempio n. 11
0
/** \brief Print an ASCII or Unicode character.
 *
 *  Print an ASCII or Unicode character at the given coordinates, using
 *  the default foreground and background colour values.
 *
 *  If the coordinates are outside the canvas boundaries, nothing is printed.
 *  If a fullwidth Unicode character gets overwritten, its remaining visible
 *  parts are replaced with spaces. If the canvas' boundaries would split the
 *  fullwidth character in two, a space is printed instead.
 *
 *  The behaviour when printing non-printable characters or invalid UTF-32
 *  characters is undefined. To print a sequence of bytes forming an UTF-8
 *  character instead of an UTF-32 character, use the caca_put_str() function.
 *
 *  This function returns the width of the printed character. If it is a
 *  fullwidth character, 2 is returned. Otherwise, 1 is returned.
 *
 *  This function never fails.
 *
 *  \param cv A handle to the libcaca canvas.
 *  \param x X coordinate.
 *  \param y Y coordinate.
 *  \param ch The character to print.
 *  \return The width of the printed character: 2 for a fullwidth character,
 *          1 otherwise.
 */
int caca_put_char(caca_canvas_t *cv, int x, int y, uint32_t ch)
{
    uint32_t *curchar, *curattr, attr;
    int fullwidth, xmin, xmax, ret;

    if(ch == CACA_MAGIC_FULLWIDTH)
        return 1;

    fullwidth = caca_utf32_is_fullwidth(ch);
    ret = fullwidth ? 2 : 1;

    if(x >= (int)cv->width || y < 0 || y >= (int)cv->height)
        return ret;

    if(x == -1 && fullwidth)
    {
        x = 0;
        ch = ' ';
        fullwidth = 0;
    }
    else if(x < 0)
        return ret;

    curchar = cv->chars + x + y * cv->width;
    curattr = cv->attrs + x + y * cv->width;
    attr = cv->curattr;

    xmin = xmax = x;

    /* When overwriting the right part of a fullwidth character,
     * replace its left part with a space. */
    if(x && curchar[0] == CACA_MAGIC_FULLWIDTH)
    {
        curchar[-1] = ' ';
        xmin--;
    }

    if(fullwidth)
    {
        if(x + 1 == (int)cv->width)
            ch = ' ';
        else
        {
            xmax++;

            /* When overwriting the left part of a fullwidth character,
             * replace its right part with a space. */
            if(x + 2 < (int)cv->width && curchar[2] == CACA_MAGIC_FULLWIDTH)
            {
                curchar[2] = ' ';
                xmax++;
            }

            curchar[1] = CACA_MAGIC_FULLWIDTH;
            curattr[1] = attr;
        }
    }
    else
    {
        /* When overwriting the left part of a fullwidth character,
         * replace its right part with a space. */
        if(x + 1 != (int)cv->width && curchar[1] == CACA_MAGIC_FULLWIDTH)
        {
            curchar[1] = ' ';
            xmax++;
        }
    }

    /* Only add a dirty rectangle if we are pasting a different character
     * or attribute at that place. This does not account for inconsistencies
     * in the canvas, ie. if CACA_MAGIC_FULLWIDTH lies at illegal places,
     * but it's the caller's responsibility not to corrupt the contents. */
    if(!cv->dirty_disabled
        && (curchar[0] != ch || curattr[0] != attr))
        caca_add_dirty_rect(cv, xmin, y, xmax - xmin + 1, 1);

    curchar[0] = ch;
    curattr[0] = attr;

    return ret;
}
Esempio n. 12
0
int caca_resize(caca_canvas_t *cv, int width, int height)
{
    int x, y, f, old_width, old_height, new_size, old_size;

    old_width = cv->width;
    old_height = cv->height;
    old_size = old_width * old_height;

    _caca_save_frame_info(cv);

    /* Preload new width and height values into the canvas to optimise
     * dirty rectangle handling */
    cv->width = width;
    cv->height = height;
    new_size = width * height;

    /* If width or height is smaller (or both), we have the opportunity to
     * reduce or even remove dirty rectangles */
    if(width < old_width || height < old_height)
        _caca_clip_dirty_rect_list(cv);

    /* Step 1: if new area is bigger, resize the memory area now. */
    if(new_size > old_size)
    {
        for(f = 0; f < cv->framecount; f++)
        {
            cv->frames[f].chars = realloc(cv->frames[f].chars,
                                          new_size * sizeof(uint32_t));
            cv->frames[f].attrs = realloc(cv->frames[f].attrs,
                                          new_size * sizeof(uint32_t));
            if(new_size && (!cv->frames[f].chars || !cv->frames[f].attrs))
            {
                seterrno(ENOMEM);
                return -1;
            }
        }
    }

    /* Step 2: move line data if necessary. */
    if(width == old_width)
    {
        /* Width did not change, which means we do not need to move data. */
        ;
    }
    else if(width > old_width)
    {
        /* New width is bigger than old width, which means we need to
         * copy lines starting from the bottom of the screen otherwise
         * we will overwrite information. */
        for(f = 0; f < cv->framecount; f++)
        {
            uint32_t *chars = cv->frames[f].chars;
            uint32_t *attrs = cv->frames[f].attrs;

            for(y = height < old_height ? height : old_height; y--; )
            {
                uint32_t attr = cv->frames[f].curattr;

                for(x = old_width; x--; )
                {
                    chars[y * width + x] = chars[y * old_width + x];
                    attrs[y * width + x] = attrs[y * old_width + x];
                }

                /* Zero the end of the line */
                for(x = width - old_width; x--; )
                {
                    chars[y * width + old_width + x] = (uint32_t)' ';
                    attrs[y * width + old_width + x] = attr;
                }
            }
        }

        if(!cv->dirty_disabled)
            caca_add_dirty_rect(cv, old_width, 0,
                                width - old_width, old_height);
    }
    else
    {
        /* New width is smaller. Copy as many lines as possible. Ignore
         * the first line, it is already in place. */
        int lines = height < old_height ? height : old_height;

        for(f = 0; f < cv->framecount; f++)
        {
            uint32_t *chars = cv->frames[f].chars;
            uint32_t *attrs = cv->frames[f].attrs;

            for(y = 1; y < lines; y++)
            {
                for(x = 0; x < width; x++)
                {
                    chars[y * width + x] = chars[y * old_width + x];
                    attrs[y * width + x] = attrs[y * old_width + x];
                }
            }
        }
    }

    /* Step 3: fill the bottom of the new screen if necessary. */
    if(height > old_height)
    {
        for(f = 0; f < cv->framecount; f++)
        {
            uint32_t *chars = cv->frames[f].chars;
            uint32_t *attrs = cv->frames[f].attrs;
            uint32_t attr = cv->frames[f].curattr;

            /* Zero the bottom of the screen */
            for(x = (height - old_height) * width; x--; )
            {
                chars[old_height * width + x] = (uint32_t)' ';
                attrs[old_height * width + x] = attr;
            }
        }

        if(!cv->dirty_disabled)
            caca_add_dirty_rect(cv, 0, old_height,
                                old_width, height - old_height);
    }

    /* If both width and height are larger, there is a new dirty rectangle
     * that needs to be created in the lower right corner. */
    if(!cv->dirty_disabled &&
        width > old_width && height > old_height)
        caca_add_dirty_rect(cv, old_width, old_height,
                            width - old_width, height - old_height);

    /* Step 4: if new area is smaller, resize memory area now. */
    if(new_size < old_size)
    {
        for(f = 0; f < cv->framecount; f++)
        {
            cv->frames[f].chars = realloc(cv->frames[f].chars,
                                          new_size * sizeof(uint32_t));
            cv->frames[f].attrs = realloc(cv->frames[f].attrs,
                                          new_size * sizeof(uint32_t));
            if(new_size && (!cv->frames[f].chars || !cv->frames[f].attrs))
            {
                seterrno(ENOMEM);
                return -1;
            }
        }
    }

    /* Set new size */
    for(f = 0; f < cv->framecount; f++)
    {
        if(cv->frames[f].x > (int)width)
            cv->frames[f].x = width;
        if(cv->frames[f].y > (int)height)
            cv->frames[f].y = height;

        cv->frames[f].width = width;
        cv->frames[f].height = height;
    }

    /* Reset the current frame shortcuts */
    _caca_load_frame_info(cv);

    return 0;
}
Esempio n. 13
0
static int ncurses_init_graphics(caca_display_t *dp)
{
    static int curses_colors[] =
    {
        /* Standard curses colours */
        COLOR_BLACK,
        COLOR_BLUE,
        COLOR_GREEN,
        COLOR_CYAN,
        COLOR_RED,
        COLOR_MAGENTA,
        COLOR_YELLOW,
        COLOR_WHITE,
        /* Extra values for xterm-16color */
        COLOR_BLACK + 8,
        COLOR_BLUE + 8,
        COLOR_GREEN + 8,
        COLOR_CYAN + 8,
        COLOR_RED + 8,
        COLOR_MAGENTA + 8,
        COLOR_YELLOW + 8,
        COLOR_WHITE + 8
    };

    mmask_t newmask;
    int fg, bg, max;

    dp->drv.p = malloc(sizeof(struct driver_private));

#if defined HAVE_GETENV && defined HAVE_PUTENV
    ncurses_install_terminal(dp);
#endif

#if defined HAVE_SIGNAL
    sigwinch_d = dp;
    signal(SIGWINCH, sigwinch_handler);
#endif

#if defined HAVE_LOCALE_H
    setlocale(LC_ALL, "");
#endif

    _caca_set_term_title("caca for ncurses");

    initscr();
    keypad(stdscr, TRUE);
    nonl();
    raw();
    noecho();
    nodelay(stdscr, TRUE);
    curs_set(0);

    /* Activate mouse */
    newmask = REPORT_MOUSE_POSITION | ALL_MOUSE_EVENTS;
    mousemask(newmask, &dp->drv.p->oldmask);
    mouseinterval(-1); /* No click emulation */

    /* Set the escape delay to a ridiculously low value */
    ESCDELAY = 10;

    /* Activate colour */
    start_color();

    /* If COLORS == 16, it means the terminal supports full bright colours
     * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
     * we can build 16*16 colour pairs.
     * If COLORS == 8, it means the terminal does not know about bright
     * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
     * and \e[5m). We can only build 8*8 colour pairs. */
    max = COLORS >= 16 ? 16 : 8;

    for(bg = 0; bg < max; bg++)
        for(fg = 0; fg < max; fg++)
        {
            /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
             * is light gray on black. Some terminals don't like this
             * colour pair to be redefined. */
            int col = ((max + 7 - fg) % max) + max * bg;
            init_pair(col, curses_colors[fg], curses_colors[bg]);
            dp->drv.p->attr[fg + 16 * bg] = COLOR_PAIR(col);

            if(max == 8)
            {
                /* Bright fg on simple bg */
                dp->drv.p->attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
                /* Simple fg on bright bg */
                dp->drv.p->attr[fg + 16 * (bg + 8)] = A_BLINK
                                                    | COLOR_PAIR(col);
                /* Bright fg on bright bg */
                dp->drv.p->attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
                                                        | COLOR_PAIR(col);
            }
        }

    caca_add_dirty_rect(dp->cv, 0, 0, dp->cv->width, dp->cv->height);
    dp->resize.allow = 1;
    caca_set_canvas_size(dp->cv, COLS, LINES);
    dp->resize.allow = 0;

    return 0;
}
Esempio n. 14
0
static int slang_init_graphics(caca_display_t *dp)
{
    dp->drv.p = malloc(sizeof(struct driver_private));
    dp->drv.p->sigint_event = 0;

#if defined(HAVE_GETENV) && defined(HAVE_PUTENV)
    slang_install_terminal(dp);
#endif

#if defined(HAVE_SIGNAL)
    sigwinch_d = dp;
    signal(SIGWINCH, sigwinch_handler);
#endif

    _caca_set_term_title("caca for S-Lang");

    /* Initialise slang library */
    SLsig_block_signals();
    /* Disable SLang's own SIGINT on ctrl-c */
    SLang_set_abort_signal(default_sigint);

    SLtt_get_terminfo();

    if(SLkp_init() == -1)
    {
        SLsig_unblock_signals();
        return -1;
    }

    SLang_init_tty(-1, 0, 1);

    if(SLsmg_init_smg() == -1)
    {
        SLsig_unblock_signals();
        return -1;
    }

    SLsmg_cls();
    SLtt_set_cursor_visibility(0);
    SLkp_define_keysym("\e[M", 1001);
    SLtt_set_mouse_mode(1, 0);
    SLsmg_refresh();

    /* Disable scrolling so that hashmap scrolling optimization code
     * does not cause ugly refreshes due to slow terminals */
    SLtt_Term_Cannot_Scroll = 1;

    slang_init_palette();

#if defined(VMS) || defined(REAL_UNIX_SYSTEM)
    /* Disable alt charset support so that we get a chance to have all
     * 256 colour pairs */
    SLtt_Has_Alt_Charset = 0;
#endif

#ifdef HAVE_SLSMG_UTF8_ENABLE
    SLsmg_utf8_enable(1); /* 1 == force, 0 == disable, -1 == autodetect */
    SLtt_utf8_enable(1);
#endif

    caca_add_dirty_rect(dp->cv, 0, 0, dp->cv->width, dp->cv->height);
    dp->resize.allow = 1;
    caca_set_canvas_size(dp->cv, SLtt_Screen_Cols, SLtt_Screen_Rows);
    dp->resize.allow = 0;

    SLsig_unblock_signals();

    return 0;
}
Esempio n. 15
0
/** \brief Rotate and stretch a canvas, 90 degrees clockwise.
 *
 *  Apply a 270-degree transformation to a canvas, choosing characters
 *  that look like the rotated version wherever possible. Some characters
 *  will stay unchanged by the process, some others will be replaced by
 *  close equivalents. Fullwidth characters will be lost. The operation is
 *  not guaranteed to be reversible at all.
 *
 *  Note that the width and height of the canvas are swapped, causing its
 *  aspect ratio to look stretched.
 *
 *  If an error occurs, -1 is returned and \b errno is set accordingly:
 *  - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
 *  - \c ENOMEM Not enough memory to allocate the new canvas size. If this
 *    happens, the previous canvas handle is still valid.
 *
 *  \param cv The canvas to rotate right.
 *  \return 0 in case of success, -1 if an error occurred.
 */
int caca_stretch_right(caca_canvas_t *cv)
{
    uint32_t *newchars, *newattrs;
    int x, y;

    if(cv->refcount)
    {
        seterrno(EBUSY);
        return -1;
    }

    /* Save the current frame shortcuts */
    _caca_save_frame_info(cv);

    newchars = malloc(cv->width * cv->height * sizeof(uint32_t));
    if(!newchars)
    {
        seterrno(ENOMEM);
        return -1;
    }

    newattrs = malloc(cv->width * cv->height * sizeof(uint32_t));
    if(!newattrs)
    {
        free(newchars);
        seterrno(ENOMEM);
        return -1;
    }

    for(y = 0; y < cv->height; y++)
    {
        for(x = 0; x < cv->width; x++)
        {
            uint32_t ch, attr;

            ch = cv->chars[cv->width * y + x];
            attr = cv->attrs[cv->width * y + x];

            /* FIXME: do something about fullwidth characters */
            ch = rightchar(ch);

            newchars[cv->height * x + cv->height - 1 - y] = ch;
            newattrs[cv->height * x + cv->height - 1 - y] = attr;
        }
    }

    free(cv->chars);
    free(cv->attrs);

    /* Swap X and Y information */
    x = cv->frames[cv->frame].x;
    y = cv->frames[cv->frame].y;
    cv->frames[cv->frame].x = cv->height - 1 - y;
    cv->frames[cv->frame].y = x;

    x = cv->frames[cv->frame].handlex;
    y = cv->frames[cv->frame].handley;
    cv->frames[cv->frame].handlex = cv->height - 1 - y;
    cv->frames[cv->frame].handley = x;

    cv->frames[cv->frame].width = cv->height;
    cv->frames[cv->frame].height = cv->width;

    cv->frames[cv->frame].chars = newchars;
    cv->frames[cv->frame].attrs = newattrs;

    /* Reset the current frame shortcuts */
    _caca_load_frame_info(cv);

    caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);

    return 0;
}
Esempio n. 16
0
/** \brief Rotate a canvas, 90 degrees counterclockwise.
 *
 *  Apply a 90-degree transformation to a canvas, choosing characters
 *  that look like the rotated version wherever possible. Characters cells
 *  are rotated two-by-two. Some characters will stay unchanged by the
 *  process, some others will be replaced by close equivalents. Fullwidth
 *  characters at odd horizontal coordinates will be lost. The operation is
 *  not guaranteed to be reversible at all.
 *
 *  Note that the width of the canvas is divided by two and becomes the
 *  new height. Height is multiplied by two and becomes the new width. If
 *  the original width is an odd number, the division is rounded up.
 *
 *  If an error occurs, -1 is returned and \b errno is set accordingly:
 *  - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
 *  - \c ENOMEM Not enough memory to allocate the new canvas size. If this
 *    happens, the previous canvas handle is still valid.
 *
 *  \param cv The canvas to rotate right.
 *  \return 0 in case of success, -1 if an error occurred.
 */
int caca_rotate_right(caca_canvas_t *cv)
{
    uint32_t *newchars, *newattrs;
    int x, y, w2, h2;

    if(cv->refcount)
    {
        seterrno(EBUSY);
        return -1;
    }

    /* Save the current frame shortcuts */
    _caca_save_frame_info(cv);

    w2 = (cv->width + 1) / 2;
    h2 = cv->height;

    newchars = malloc(w2 * h2 * 2 * sizeof(uint32_t));
    if(!newchars)
    {
        seterrno(ENOMEM);
        return -1;
    }

    newattrs = malloc(w2 * h2 * 2 * sizeof(uint32_t));
    if(!newattrs)
    {
        free(newchars);
        seterrno(ENOMEM);
        return -1;
    }

    for(y = 0; y < h2; y++)
    {
        for(x = 0; x < w2; x++)
        {
            uint32_t pair[2], attr1, attr2;

            pair[0] = cv->chars[cv->width * y + x * 2];
            attr1 = cv->attrs[cv->width * y + x * 2];

            if((cv->width & 1) && x == w2 - 1)
            {
                /* Special case: odd column */
                pair[1] = ' ';
                attr2 = attr1;
            }
            else
            {
                pair[1] = cv->chars[cv->width * y + x * 2 + 1];
                attr2 = cv->attrs[cv->width * y + x * 2 + 1];
            }

            /* If one of the characters is a space, we simply ignore
             * its colour attributes. Otherwise the resulting characters
             * may have totally wrong colours. */
            if(pair[0] == ' ')
                attr1 = attr2;
            else if(pair[1] == ' ')
                attr2 = attr1;

            rightpair(pair);

            newchars[(h2 * x + h2 - 1 - y) * 2] = pair[0];
            newattrs[(h2 * x + h2 - 1 - y) * 2] = attr1;
            newchars[(h2 * x + h2 - 1 - y) * 2 + 1] = pair[1];
            newattrs[(h2 * x + h2 - 1 - y) * 2 + 1] = attr2;
        }
    }

    free(cv->chars);
    free(cv->attrs);

    /* Swap X and Y information */
    x = cv->frames[cv->frame].x;
    y = cv->frames[cv->frame].y;
    cv->frames[cv->frame].x = (cv->height - 1 - y) * 2;
    cv->frames[cv->frame].y = x / 2;

    x = cv->frames[cv->frame].handlex;
    y = cv->frames[cv->frame].handley;
    cv->frames[cv->frame].handlex = (cv->height - 1 - y) * 2;
    cv->frames[cv->frame].handley = x / 2;

    cv->frames[cv->frame].width = cv->height * 2;
    cv->frames[cv->frame].height = (cv->width + 1) / 2;

    cv->frames[cv->frame].chars = newchars;
    cv->frames[cv->frame].attrs = newattrs;

    /* Reset the current frame shortcuts */
    _caca_load_frame_info(cv);

    if(!cv->dirty_disabled)
        caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);

    return 0;
}