[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.2

1.2     ! ray         1: /* $OpenBSD: grid.c,v 1.1 2009/06/01 22:58:49 nicm Exp $ */
1.1       nicm        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: }