X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=ncurses%2Fbase%2Fwresize.c;h=30718b8878fd660766b5c90863fd661d240421bf;hp=8121ff154dd58085c1d567821d9d12e104043700;hb=2db461ea0b1b29c142e3000d830b520c946e385b;hpb=b1f61d9f3aa244512045a6b02e759825d7049d34 diff --git a/ncurses/base/wresize.c b/ncurses/base/wresize.c index 8121ff15..30718b88 100644 --- a/ncurses/base/wresize.c +++ b/ncurses/base/wresize.c @@ -1,5 +1,6 @@ /**************************************************************************** - * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc. * + * Copyright 2019,2020 Thomas E. Dickey * + * Copyright 1998-2010,2011 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -27,40 +28,100 @@ ****************************************************************************/ /**************************************************************************** - * Author: Thomas E. Dickey 1996,1997 * + * Author: Thomas E. Dickey 1996-on * + * and: Juergen Pfeifer * ****************************************************************************/ #include -MODULE_ID("$Id: wresize.c,v 1.16 2000/03/05 00:14:35 tom Exp $") +MODULE_ID("$Id: wresize.c,v 1.41 2020/04/18 21:01:00 tom Exp $") + +static int +cleanup_lines(struct ldat *data, int length) +{ + while (--length >= 0) + FreeAndNull(data[length].text); + free(data); + return ERR; +} + +/* + * If we have reallocated the ldat structs, we will have to repair pointers + * used in subwindows. + */ +static void +repair_subwindows(WINDOW *cmp) +{ + WINDOWLIST *wp; + struct ldat *pline = cmp->_line; + int row; +#ifdef USE_SP_WINDOWLIST + SCREEN *sp = _nc_screen_of(cmp); +#endif + + _nc_lock_global(curses); + + for (each_window(SP_PARM, wp)) { + WINDOW *tst = &(wp->win); + + if (tst->_parent == cmp) { + +#define REPAIR1(field, limit) \ + if (tst->field > cmp->limit) \ + tst->field = cmp->limit + + REPAIR1(_pary, _maxy); + REPAIR1(_parx, _maxx); + +#define REPAIR2(field, limit) \ + if (tst->limit + tst->field > cmp->limit) \ + tst->limit = (NCURSES_SIZE_T) (cmp->limit - tst->field) + + REPAIR2(_pary, _maxy); + REPAIR2(_parx, _maxx); + +#define REPAIR3(field, limit) \ + if (tst->field > tst->limit) \ + tst->field = tst->limit + + REPAIR3(_cury, _maxy); + REPAIR3(_curx, _maxx); + + REPAIR3(_regtop, _maxy); + REPAIR3(_regbottom, _maxy); + + for (row = 0; row <= tst->_maxy; ++row) { + tst->_line[row].text = &pline[tst->_pary + row].text[tst->_parx]; + } + repair_subwindows(tst); + } + } + _nc_unlock_global(curses); +} /* * Reallocate a curses WINDOW struct to either shrink or grow to the specified * new lines/columns. If it grows, the new character cells are filled with * blanks. The application is responsible for repainting the blank area. */ - -#define DOALLOC(p,t,n) typeRealloc(t, n, p) -#define ld_ALLOC(p,n) DOALLOC(p,struct ldat,n) -#define c_ALLOC(p,n) DOALLOC(p,chtype,n) - -int +NCURSES_EXPORT(int) wresize(WINDOW *win, int ToLines, int ToCols) { - register int row; - int size_x, size_y; + int col, row, size_x, size_y; struct ldat *pline; - chtype blank; + struct ldat *new_lines = 0; #ifdef TRACE - T((T_CALLED("wresize(%p,%d,%d)"), win, ToLines, ToCols)); + T((T_CALLED("wresize(%p,%d,%d)"), (void *) win, ToLines, ToCols)); if (win) { - TR(TRACE_UPDATE, ("...beg (%d, %d), max(%d,%d), reg(%d,%d)", - win->_begy, win->_begx, - win->_maxy, win->_maxx, - win->_regtop, win->_regbottom)); - if (_nc_tracing & TRACE_UPDATE) + TR(TRACE_UPDATE, ("...beg (%ld, %ld), max(%ld,%ld), reg(%ld,%ld)", + (long) win->_begy, (long) win->_begx, + (long) win->_maxy, (long) win->_maxx, + (long) win->_regtop, (long) win->_regbottom)); + if (USE_TRACEF(TRACE_UPDATE)) { _tracedump("...before", win); + _nc_unlock_global(tracef); + } } #endif @@ -90,71 +151,100 @@ wresize(WINDOW *win, int ToLines, int ToCols) } /* - * If the number of lines has changed, adjust the size of the overall - * vector: + * Allocate new memory as needed. Do the allocations without modifying + * the original window, in case an allocation fails. Always allocate + * (at least temporarily) the array pointing to the individual lines. + */ + new_lines = typeCalloc(struct ldat, (unsigned) (ToLines + 1)); + if (new_lines == 0) + returnCode(ERR); + + /* + * For each line in the target, allocate or adjust pointers for the + * corresponding text, depending on whether this is a window or a + * subwindow. */ - if (ToLines != size_y) { + for (row = 0; row <= ToLines; ++row) { + int begin = (row > size_y) ? 0 : (size_x + 1); + int end = ToCols; + NCURSES_CH_T *s; + if (!(win->_flags & _SUBWIN)) { - for (row = ToLines + 1; row <= size_y; row++) - free((char *) (win->_line[row].text)); + if (row <= size_y) { + if (ToCols != size_x) { + s = typeMalloc(NCURSES_CH_T, (unsigned) ToCols + 1); + if (s == 0) + returnCode(cleanup_lines(new_lines, row)); + for (col = 0; col <= ToCols; ++col) { + bool valid = (col <= size_x); + if_WIDEC({ + if (col == ToCols + && col < size_x + && isWidecBase(win->_line[row].text[col])) { + valid = FALSE; + } + }); + s[col] = (valid + ? win->_line[row].text[col] + : win->_nc_bkgd); + } + } else { + s = win->_line[row].text; + } + } else { + s = typeMalloc(NCURSES_CH_T, (unsigned) ToCols + 1); + if (s == 0) + returnCode(cleanup_lines(new_lines, row)); + for (col = 0; col <= ToCols; ++col) + s[col] = win->_nc_bkgd; + } + } else if (pline != 0 && pline[win->_pary + row].text != 0) { + s = &pline[win->_pary + row].text[win->_parx]; + } else { + s = 0; } - win->_line = ld_ALLOC(win->_line, ToLines + 1); - if (win->_line == 0) - returnCode(ERR); - - for (row = size_y + 1; row <= ToLines; row++) { - win->_line[row].text = 0; - win->_line[row].firstchar = 0; - win->_line[row].lastchar = ToCols; - if ((win->_flags & _SUBWIN)) { - win->_line[row].text = - &pline[win->_pary + row].text[win->_parx]; + if_USE_SCROLL_HINTS(new_lines[row].oldindex = row); + if (row <= size_y) { + new_lines[row].firstchar = win->_line[row].firstchar; + new_lines[row].lastchar = win->_line[row].lastchar; + } + if ((ToCols != size_x) || (row > size_y)) { + if (end >= begin) { /* growing */ + if (new_lines[row].firstchar < begin) + new_lines[row].firstchar = (NCURSES_SIZE_T) begin; + } else { /* shrinking */ + new_lines[row].firstchar = 0; } + new_lines[row].lastchar = (NCURSES_SIZE_T) ToCols; } + new_lines[row].text = s; } /* - * Adjust the width of the columns: + * Dispose of unwanted memory. */ - blank = _nc_background(win); - for (row = 0; row <= ToLines; row++) { - chtype *s = win->_line[row].text; - int begin = (s == 0) ? 0 : size_x + 1; - int end = ToCols; - - if_USE_SCROLL_HINTS(win->_line[row].oldindex = row); - - if (ToCols != size_x || s == 0) { - if (!(win->_flags & _SUBWIN)) { - win->_line[row].text = s = c_ALLOC(s, ToCols + 1); - if (win->_line[row].text == 0) - returnCode(ERR); - } else if (s == 0) { - win->_line[row].text = s = - &pline[win->_pary + row].text[win->_parx]; + if (!(win->_flags & _SUBWIN)) { + if (ToCols == size_x) { + for (row = ToLines + 1; row <= size_y; row++) { + FreeAndNull(win->_line[row].text); } - - if (end >= begin) { /* growing */ - if (win->_line[row].firstchar < begin) - win->_line[row].firstchar = begin; - win->_line[row].lastchar = ToCols; - do { - s[end] = blank; - } while (--end >= begin); - } else { /* shrinking */ - win->_line[row].firstchar = 0; - win->_line[row].lastchar = ToCols; + } else { + for (row = 0; row <= size_y; row++) { + FreeAndNull(win->_line[row].text); } } } + FreeAndNull(win->_line); + win->_line = new_lines; + /* * Finally, adjust the parameters showing screen size and cursor * position: */ - win->_maxx = ToCols; - win->_maxy = ToLines; + win->_maxx = (NCURSES_SIZE_T) ToCols; + win->_maxy = (NCURSES_SIZE_T) ToLines; if (win->_regtop > win->_maxy) win->_regtop = win->_maxy; @@ -167,13 +257,21 @@ wresize(WINDOW *win, int ToLines, int ToCols) if (win->_cury > win->_maxy) win->_cury = win->_maxy; + /* + * Check for subwindows of this one, and readjust pointers to our text, + * if needed. + */ + repair_subwindows(win); + #ifdef TRACE - TR(TRACE_UPDATE, ("...beg (%d, %d), max(%d,%d), reg(%d,%d)", - win->_begy, win->_begx, - win->_maxy, win->_maxx, - win->_regtop, win->_regbottom)); - if (_nc_tracing & TRACE_UPDATE) + TR(TRACE_UPDATE, ("...beg (%ld, %ld), max(%ld,%ld), reg(%ld,%ld)", + (long) win->_begy, (long) win->_begx, + (long) win->_maxy, (long) win->_maxx, + (long) win->_regtop, (long) win->_regbottom)); + if (USE_TRACEF(TRACE_UPDATE)) { _tracedump("...after:", win); + _nc_unlock_global(tracef); + } #endif returnCode(OK); }