[BACK]Return to grid.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/grid.c, Revision 1.1

1.1     ! nicm        1: /* $OpenBSD$ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
        !            15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
        !            16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: #include <sys/types.h>
        !            20:
        !            21: #include <string.h>
        !            22:
        !            23: #include "tmux.h"
        !            24:
        !            25: /*
        !            26:  * Grid data. This is the basic data structure that represents what is shown on
        !            27:  * screen.
        !            28:  *
        !            29:  * A grid is a grid of cells (struct grid_cell). Lines are not allocated until
        !            30:  * cells in that line are written to. The grid is split into history and
        !            31:  * viewable data with the history starting at row (line) 0 and extending to
        !            32:  * (hsize - 1); from hsize to hsize + (sy - 1) is the viewable data. All
        !            33:  * functions in this file work on absolute coordinates, grid-view.c has
        !            34:  * functions which work on the screen data.
        !            35:  */
        !            36:
        !            37: /* Default grid cell data. */
        !            38: const struct grid_cell grid_default_cell = { 0, 0, 8, 8, ' ' };
        !            39:
        !            40: #define grid_put_cell(gd, px, py, gc) do {                     \
        !            41:        memcpy(&gd->data[py][px], gc, sizeof gd->data[py][px]); \
        !            42: } while (0)
        !            43: #define grid_put_utf8(gd, px, py, gc) do {                     \
        !            44:        memcpy(&gd->udata[py][px], gc, sizeof gd->udata[py][px]); \
        !            45: } while (0)
        !            46:
        !            47: int    grid_check_x(struct grid *, u_int);
        !            48: int    grid_check_y(struct grid *, u_int);
        !            49:
        !            50: #ifdef DEBUG
        !            51: int
        !            52: grid_check_x(struct grid *gd, u_int px)
        !            53: {
        !            54:        if ((px) >= (gd)->sx)
        !            55:                log_fatalx("x out of range: %u", px);
        !            56:        return (0);
        !            57: }
        !            58:
        !            59: int
        !            60: grid_check_y(struct grid *gd, u_int py)
        !            61: {
        !            62:        if ((py) >= (gd)->hsize + (gd)->sy)
        !            63:                log_fatalx("y out of range: %u", py);
        !            64:        return (0);
        !            65: }
        !            66: #else
        !            67: int
        !            68: grid_check_x(struct grid *gd, u_int px)
        !            69: {
        !            70:        if ((px) >= (gd)->sx) {
        !            71:                log_debug("x out of range: %u", px);
        !            72:                return (-1);
        !            73:        }
        !            74:        return (0);
        !            75: }
        !            76:
        !            77: int
        !            78: grid_check_y(struct grid *gd, u_int py)
        !            79: {
        !            80:        if ((py) >= (gd)->hsize + (gd)->sy) {
        !            81:                log_debug("y out of range: %u", py);
        !            82:                return (-1);
        !            83:        }
        !            84:        return (0);
        !            85: }
        !            86: #endif
        !            87:
        !            88: /* Create a new grid. */
        !            89: struct grid *
        !            90: grid_create(u_int sx, u_int sy, u_int hlimit)
        !            91: {
        !            92:        struct grid     *gd;
        !            93:
        !            94:        gd = xmalloc(sizeof *gd);
        !            95:        gd->sx = sx;
        !            96:        gd->sy = sy;
        !            97:
        !            98:        gd->hsize = 0;
        !            99:        gd->hlimit = hlimit;
        !           100:
        !           101:        gd->size = xcalloc(gd->sy, sizeof *gd->size);
        !           102:        gd->data = xcalloc(gd->sy, sizeof *gd->data);
        !           103:
        !           104:        gd->usize = xcalloc(gd->sy, sizeof *gd->usize);
        !           105:        gd->udata = xcalloc(gd->sy, sizeof *gd->udata);
        !           106:
        !           107:        return (gd);
        !           108: }
        !           109:
        !           110: /* Destroy grid. */
        !           111: void
        !           112: grid_destroy(struct grid *gd)
        !           113: {
        !           114:        u_int   yy;
        !           115:
        !           116:        for (yy = 0; yy < gd->hsize + gd->sy; yy++) {
        !           117:                if (gd->udata[yy] != NULL)
        !           118:                        xfree(gd->udata[yy]);
        !           119:                if (gd->data[yy] != NULL)
        !           120:                        xfree(gd->data[yy]);
        !           121:        }
        !           122:
        !           123:        if (gd->udata != NULL)
        !           124:                xfree(gd->udata);
        !           125:        if (gd->usize != NULL)
        !           126:                xfree(gd->usize);
        !           127:
        !           128:        if (gd->data != NULL)
        !           129:                xfree(gd->data);
        !           130:        if (gd->size != NULL)
        !           131:                xfree(gd->size);
        !           132:
        !           133:        xfree(gd);
        !           134: }
        !           135:
        !           136: /* Compare grids. */
        !           137: int
        !           138: grid_compare(struct grid *ga, struct grid *gb)
        !           139: {
        !           140:        struct grid_cell        *gca, *gcb;
        !           141:        struct grid_utf8        *gua, *gub;
        !           142:        u_int                    xx, yy;
        !           143:
        !           144:        if (ga->sx != gb->sx || ga->sy != ga->sy)
        !           145:                return (1);
        !           146:
        !           147:        for (yy = 0; yy < ga->sy; yy++) {
        !           148:                if (ga->size[yy] != gb->size[yy])
        !           149:                        return (1);
        !           150:                for (xx = 0; xx < ga->sx; xx++) {
        !           151:                        gca = &ga->data[yy][xx];
        !           152:                        gcb = &gb->data[yy][xx];
        !           153:                        if (memcmp(gca, gcb, sizeof (struct grid_cell)) != 0)
        !           154:                                return (1);
        !           155:                        if (!(gca->flags & GRID_FLAG_UTF8))
        !           156:                                continue;
        !           157:                        gua = &ga->udata[yy][xx];
        !           158:                        gub = &gb->udata[yy][xx];
        !           159:                        if (memcmp(gua, gub, sizeof (struct grid_utf8)) != 0)
        !           160:                                return (1);
        !           161:                }
        !           162:        }
        !           163:
        !           164:        return (0);
        !           165: }
        !           166:
        !           167: /* Scroll a line into the history. */
        !           168: void
        !           169: grid_scroll_line(struct grid *gd)
        !           170: {
        !           171:        u_int   yy;
        !           172:
        !           173:        GRID_DEBUG(gd, "");
        !           174:
        !           175:        if (gd->hsize >= gd->hlimit - 1) {
        !           176:                /* If the limit is hit, free the bottom 10% and shift up. */
        !           177:                yy = gd->hlimit / 10;
        !           178:                if (yy < 1)
        !           179:                        yy = 1;
        !           180:
        !           181:                grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy);
        !           182:                gd->hsize -= yy;
        !           183:        }
        !           184:
        !           185:        yy = gd->hsize + gd->sy;
        !           186:
        !           187:        gd->size = xrealloc(gd->size, yy + 1, sizeof *gd->size);
        !           188:        gd->size[yy] = 0;
        !           189:        gd->data = xrealloc(gd->data, yy + 1, sizeof *gd->data);
        !           190:        gd->data[yy] = NULL;
        !           191:
        !           192:        gd->usize = xrealloc(gd->usize, yy + 1, sizeof *gd->usize);
        !           193:        gd->usize[yy] = 0;
        !           194:        gd->udata = xrealloc(gd->udata, yy + 1, sizeof *gd->udata);
        !           195:        gd->udata[yy] = NULL;
        !           196:
        !           197:        gd->hsize++;
        !           198: }
        !           199:
        !           200: /* Reduce line to fit to cell. */
        !           201: void
        !           202: grid_reduce_line(struct grid *gd, u_int py, u_int sx)
        !           203: {
        !           204:        if (sx < gd->size[py]) {
        !           205:                gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data);
        !           206:                gd->size[py] = sx;
        !           207:        }
        !           208:        if (sx < gd->usize[py]) {
        !           209:                gd->udata[py] = xrealloc(gd->udata[py], sx, sizeof **gd->udata);
        !           210:                gd->usize[py] = sx;
        !           211:        }
        !           212: }
        !           213:
        !           214: /* Expand line to fit to cell. */
        !           215: void
        !           216: grid_expand_line(struct grid *gd, u_int py, u_int sx)
        !           217: {
        !           218:        u_int   xx;
        !           219:
        !           220:        if (sx <= gd->size[py])
        !           221:                return;
        !           222:
        !           223:        gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data);
        !           224:        for (xx = gd->size[py]; xx < sx; xx++)
        !           225:                grid_put_cell(gd, xx, py, &grid_default_cell);
        !           226:        gd->size[py] = sx;
        !           227: }
        !           228:
        !           229: /* Expand line to fit to cell for UTF-8. */
        !           230: void
        !           231: grid_expand_line_utf8(struct grid *gd, u_int py, u_int sx)
        !           232: {
        !           233:        if (sx <= gd->usize[py])
        !           234:                return;
        !           235:
        !           236:        gd->udata[py] = xrealloc(gd->udata[py], sx, sizeof **gd->udata);
        !           237:        gd->usize[py] = sx;
        !           238: }
        !           239:
        !           240: /* Get cell for reading. */
        !           241: const struct grid_cell *
        !           242: grid_peek_cell(struct grid *gd, u_int px, u_int py)
        !           243: {
        !           244:        if (grid_check_x(gd, px) != 0)
        !           245:                return (&grid_default_cell);
        !           246:        if (grid_check_y(gd, py) != 0)
        !           247:                return (&grid_default_cell);
        !           248:
        !           249:        if (px >= gd->size[py])
        !           250:                return (&grid_default_cell);
        !           251:        return (&gd->data[py][px]);
        !           252: }
        !           253:
        !           254: /* Get cell at relative position (for writing). */
        !           255: struct grid_cell *
        !           256: grid_get_cell(struct grid *gd, u_int px, u_int py)
        !           257: {
        !           258:        if (grid_check_x(gd, px) != 0)
        !           259:                return (NULL);
        !           260:        if (grid_check_y(gd, py) != 0)
        !           261:                return (NULL);
        !           262:
        !           263:        grid_expand_line(gd, py, px + 1);
        !           264:        return (&gd->data[py][px]);
        !           265: }
        !           266:
        !           267: /* Set cell at relative position. */
        !           268: void
        !           269: grid_set_cell(
        !           270:     struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
        !           271: {
        !           272:        if (grid_check_x(gd, px) != 0)
        !           273:                return;
        !           274:        if (grid_check_y(gd, py) != 0)
        !           275:                return;
        !           276:
        !           277:        grid_expand_line(gd, py, px + 1);
        !           278:        grid_put_cell(gd, px, py, gc);
        !           279: }
        !           280:
        !           281: /* Get UTF-8 for reading. */
        !           282: const struct grid_utf8 *
        !           283: grid_peek_utf8(struct grid *gd, u_int px, u_int py)
        !           284: {
        !           285:        if (grid_check_x(gd, px) != 0)
        !           286:                return (NULL);
        !           287:        if (grid_check_y(gd, py) != 0)
        !           288:                return (NULL);
        !           289:
        !           290:        if (px >= gd->usize[py])
        !           291:                return (NULL);
        !           292:        return (&gd->udata[py][px]);
        !           293: }
        !           294:
        !           295: /* Get utf8 at relative position (for writing). */
        !           296: struct grid_utf8 *
        !           297: grid_get_utf8(struct grid *gd, u_int px, u_int py)
        !           298: {
        !           299:        if (grid_check_x(gd, px) != 0)
        !           300:                return (NULL);
        !           301:        if (grid_check_y(gd, py) != 0)
        !           302:                return (NULL);
        !           303:
        !           304:        grid_expand_line_utf8(gd, py, px + 1);
        !           305:        return (&gd->udata[py][px]);
        !           306: }
        !           307:
        !           308: /* Set utf8 at relative position. */
        !           309: void
        !           310: grid_set_utf8(
        !           311:     struct grid *gd, u_int px, u_int py, const struct grid_utf8 *gc)
        !           312: {
        !           313:        if (grid_check_x(gd, px) != 0)
        !           314:                return;
        !           315:        if (grid_check_y(gd, py) != 0)
        !           316:                return;
        !           317:
        !           318:        grid_expand_line_utf8(gd, py, px + 1);
        !           319:        grid_put_utf8(gd, px, py, gc);
        !           320: }
        !           321:
        !           322: /*
        !           323:  * Clear area. Note this is different from a fill as it just omits unallocated
        !           324:  * cells.
        !           325:  */
        !           326: void
        !           327: grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny)
        !           328: {
        !           329:        u_int   xx, yy;
        !           330:
        !           331:        GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny);
        !           332:
        !           333:        if (nx == 0 || ny == 0)
        !           334:                return;
        !           335:
        !           336:        if (px == 0 && nx == gd->sx) {
        !           337:                grid_clear_lines(gd, py, ny);
        !           338:                return;
        !           339:        }
        !           340:
        !           341:        if (grid_check_x(gd, px) != 0)
        !           342:                return;
        !           343:        if (grid_check_x(gd, px + nx - 1) != 0)
        !           344:                return;
        !           345:        if (grid_check_y(gd, py) != 0)
        !           346:                return;
        !           347:        if (grid_check_y(gd, py + ny - 1) != 0)
        !           348:                return;
        !           349:
        !           350:        for (yy = py; yy < py + ny; yy++) {
        !           351:                for (xx = px; xx < px + nx; xx++) {
        !           352:                        if (xx >= gd->size[yy])
        !           353:                                break;
        !           354:                        grid_put_cell(gd, xx, yy, &grid_default_cell);
        !           355:                }
        !           356:        }
        !           357: }
        !           358:
        !           359: /* Clear lines. This just frees and truncates the lines. */
        !           360: void
        !           361: grid_clear_lines(struct grid *gd, u_int py, u_int ny)
        !           362: {
        !           363:        u_int   yy;
        !           364:
        !           365:        GRID_DEBUG(gd, "py=%u, ny=%u", py, ny);
        !           366:
        !           367:        if (ny == 0)
        !           368:                return;
        !           369:
        !           370:        if (grid_check_y(gd, py) != 0)
        !           371:                return;
        !           372:        if (grid_check_y(gd, py + ny - 1) != 0)
        !           373:                return;
        !           374:
        !           375:        for (yy = py; yy < py + ny; yy++) {
        !           376:                if (gd->data[yy] != NULL) {
        !           377:                        xfree(gd->data[yy]);
        !           378:                        gd->data[yy] = NULL;
        !           379:                        gd->size[yy] = 0;
        !           380:                }
        !           381:                if (gd->udata[yy] != NULL) {
        !           382:                        xfree(gd->udata[yy]);
        !           383:                        gd->udata[yy] = NULL;
        !           384:                        gd->usize[yy] = 0;
        !           385:                }
        !           386:        }
        !           387: }
        !           388:
        !           389: /* Move a group of lines. */
        !           390: void
        !           391: grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny)
        !           392: {
        !           393:        u_int   yy;
        !           394:
        !           395:        GRID_DEBUG(gd, "dy=%u, py=%u, ny=%u", dy, py, ny);
        !           396:
        !           397:        if (ny == 0 || py == dy)
        !           398:                return;
        !           399:
        !           400:        if (grid_check_y(gd, py) != 0)
        !           401:                return;
        !           402:        if (grid_check_y(gd, py + ny - 1) != 0)
        !           403:                return;
        !           404:        if (grid_check_y(gd, dy) != 0)
        !           405:                return;
        !           406:        if (grid_check_y(gd, dy + ny - 1) != 0)
        !           407:                return;
        !           408:
        !           409:        /* Free any lines which are being replaced. */
        !           410:        for (yy = dy; yy < dy + ny; yy++) {
        !           411:                if (yy >= py && yy < py + ny)
        !           412:                        continue;
        !           413:                grid_clear_lines(gd, yy, 1);
        !           414:        }
        !           415:
        !           416:        memmove(&gd->data[dy], &gd->data[py], ny * (sizeof *gd->data));
        !           417:        memmove(&gd->size[dy], &gd->size[py], ny * (sizeof *gd->size));
        !           418:
        !           419:        memmove(&gd->udata[dy], &gd->udata[py], ny * (sizeof *gd->udata));
        !           420:        memmove(&gd->usize[dy], &gd->usize[py], ny * (sizeof *gd->usize));
        !           421:
        !           422:        /* Wipe any lines that have been moved (without freeing them). */
        !           423:        for (yy = py; yy < py + ny; yy++) {
        !           424:                if (yy >= dy && yy < dy + ny)
        !           425:                        continue;
        !           426:                gd->data[yy] = NULL;
        !           427:                gd->size[yy] = 0;
        !           428:                gd->udata[yy] = NULL;
        !           429:                gd->usize[yy] = 0;
        !           430:        }
        !           431: }
        !           432:
        !           433: /* Clear a group of cells. */
        !           434: void
        !           435: grid_clear_cells(struct grid *gd, u_int px, u_int py, u_int nx)
        !           436: {
        !           437:        u_int   xx;
        !           438:
        !           439:        GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx);
        !           440:
        !           441:        if (nx == 0)
        !           442:                return;
        !           443:
        !           444:        if (grid_check_x(gd, px) != 0)
        !           445:                return;
        !           446:        if (grid_check_x(gd, px + nx - 1) != 0)
        !           447:                return;
        !           448:        if (grid_check_y(gd, py) != 0)
        !           449:                return;
        !           450:
        !           451:        for (xx = px; xx < px + nx; xx++) {
        !           452:                if (xx >= gd->size[py])
        !           453:                        break;
        !           454:                grid_put_cell(gd, xx, py, &grid_default_cell);
        !           455:        }
        !           456: }
        !           457:
        !           458: /* Move a group of cells. */
        !           459: void
        !           460: grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx)
        !           461: {
        !           462:        u_int   xx;
        !           463:
        !           464:        GRID_DEBUG(gd, "dx=%u, px=%u, py=%u, nx=%u", dx, px, py, nx);
        !           465:
        !           466:        if (nx == 0 || px == dx)
        !           467:                return;
        !           468:
        !           469:        if (grid_check_x(gd, px) != 0)
        !           470:                return;
        !           471:        if (grid_check_x(gd, px + nx - 1) != 0)
        !           472:                return;
        !           473:        if (grid_check_x(gd, dx + nx - 1) != 0)
        !           474:                return;
        !           475:        if (grid_check_y(gd, py) != 0)
        !           476:                return;
        !           477:
        !           478:        grid_expand_line(gd, py, px + nx);
        !           479:        grid_expand_line(gd, py, dx + nx);
        !           480:        memmove(&gd->data[py][dx], &gd->data[py][px], nx * (sizeof **gd->data));
        !           481:
        !           482:        if (gd->udata[py] != NULL) {
        !           483:                grid_expand_line_utf8(gd, py, px + nx);
        !           484:                grid_expand_line_utf8(gd, py, dx + nx);
        !           485:                memmove(&gd->udata[py][dx],
        !           486:                    &gd->udata[py][px], nx * (sizeof **gd->udata));
        !           487:        }
        !           488:
        !           489:        /* Wipe any cells that have been moved. */
        !           490:        for (xx = px; xx < px + nx; xx++) {
        !           491:                if (xx >= dx && xx < dx + nx)
        !           492:                        continue;
        !           493:                grid_put_cell(gd, xx, py, &grid_default_cell);
        !           494:        }
        !           495: }
        !           496:
        !           497: