1 /**************************************************************************** 2 * Copyright 2019,2020 Thomas E. Dickey * 3 * Copyright 1998-2010,2011 Free Software Foundation, Inc. * 4 * * 5 * Permission is hereby granted, free of charge, to any person obtaining a * 6 * copy of this software and associated documentation files (the * 7 * "Software"), to deal in the Software without restriction, including * 8 * without limitation the rights to use, copy, modify, merge, publish, * 9 * distribute, distribute with modifications, sublicense, and/or sell * 10 * copies of the Software, and to permit persons to whom the Software is * 11 * furnished to do so, subject to the following conditions: * 12 * * 13 * The above copyright notice and this permission notice shall be included * 14 * in all copies or substantial portions of the Software. * 15 * * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 * * 24 * Except as contained in this notice, the name(s) of the above copyright * 25 * holders shall not be used in advertising or otherwise to promote the * 26 * sale, use or other dealings in this Software without prior written * 27 * authorization. * 28 ****************************************************************************/ 29 30 /**************************************************************************** 31 * Author: Thomas E. Dickey 1996-on * 32 * and: Juergen Pfeifer * 33 ****************************************************************************/ 34 35 #include <curses.priv.h> 36 37 MODULE_ID("$Id: wresize.c,v 1.41 2020/04/18 21:01:00 tom Exp $") 38 39 static int 40 cleanup_lines(struct ldat *data, int length) 41 { 42 while (--length >= 0) 43 FreeAndNull(data[length].text); 44 free(data); 45 return ERR; 46 } 47 48 /* 49 * If we have reallocated the ldat structs, we will have to repair pointers 50 * used in subwindows. 51 */ 52 static void 53 repair_subwindows(WINDOW *cmp) 54 { 55 WINDOWLIST *wp; 56 struct ldat *pline = cmp->_line; 57 int row; 58 #ifdef USE_SP_WINDOWLIST 59 SCREEN *sp = _nc_screen_of(cmp); 60 #endif 61 62 _nc_lock_global(curses); 63 64 for (each_window(SP_PARM, wp)) { 65 WINDOW *tst = &(wp->win); 66 67 if (tst->_parent == cmp) { 68 69 #define REPAIR1(field, limit) \ 70 if (tst->field > cmp->limit) \ 71 tst->field = cmp->limit 72 73 REPAIR1(_pary, _maxy); 74 REPAIR1(_parx, _maxx); 75 76 #define REPAIR2(field, limit) \ 77 if (tst->limit + tst->field > cmp->limit) \ 78 tst->limit = (NCURSES_SIZE_T) (cmp->limit - tst->field) 79 80 REPAIR2(_pary, _maxy); 81 REPAIR2(_parx, _maxx); 82 83 #define REPAIR3(field, limit) \ 84 if (tst->field > tst->limit) \ 85 tst->field = tst->limit 86 87 REPAIR3(_cury, _maxy); 88 REPAIR3(_curx, _maxx); 89 90 REPAIR3(_regtop, _maxy); 91 REPAIR3(_regbottom, _maxy); 92 93 for (row = 0; row <= tst->_maxy; ++row) { 94 tst->_line[row].text = &pline[tst->_pary + row].text[tst->_parx]; 95 } 96 repair_subwindows(tst); 97 } 98 } 99 _nc_unlock_global(curses); 100 } 101 102 /* 103 * Reallocate a curses WINDOW struct to either shrink or grow to the specified 104 * new lines/columns. If it grows, the new character cells are filled with 105 * blanks. The application is responsible for repainting the blank area. 106 */ 107 NCURSES_EXPORT(int) 108 wresize(WINDOW *win, int ToLines, int ToCols) 109 { 110 int col, row, size_x, size_y; 111 struct ldat *pline; 112 struct ldat *new_lines = 0; 113 114 #ifdef TRACE 115 T((T_CALLED("wresize(%p,%d,%d)"), (void *) win, ToLines, ToCols)); 116 if (win) { 117 TR(TRACE_UPDATE, ("...beg (%ld, %ld), max(%ld,%ld), reg(%ld,%ld)", 118 (long) win->_begy, (long) win->_begx, 119 (long) win->_maxy, (long) win->_maxx, 120 (long) win->_regtop, (long) win->_regbottom)); 121 if (USE_TRACEF(TRACE_UPDATE)) { 122 _tracedump("...before", win); 123 _nc_unlock_global(tracef); 124 } 125 } 126 #endif 127 128 if (!win || --ToLines < 0 || --ToCols < 0) 129 returnCode(ERR); 130 131 size_x = win->_maxx; 132 size_y = win->_maxy; 133 134 if (ToLines == size_y 135 && ToCols == size_x) 136 returnCode(OK); 137 138 if ((win->_flags & _SUBWIN)) { 139 /* 140 * Check if the new limits will fit into the parent window's size. If 141 * not, do not resize. We could adjust the location of the subwindow, 142 * but the application may not like that. 143 */ 144 if (win->_pary + ToLines > win->_parent->_maxy 145 || win->_parx + ToCols > win->_parent->_maxx) { 146 returnCode(ERR); 147 } 148 pline = win->_parent->_line; 149 } else { 150 pline = 0; 151 } 152 153 /* 154 * Allocate new memory as needed. Do the allocations without modifying 155 * the original window, in case an allocation fails. Always allocate 156 * (at least temporarily) the array pointing to the individual lines. 157 */ 158 new_lines = typeCalloc(struct ldat, (unsigned) (ToLines + 1)); 159 if (new_lines == 0) 160 returnCode(ERR); 161 162 /* 163 * For each line in the target, allocate or adjust pointers for the 164 * corresponding text, depending on whether this is a window or a 165 * subwindow. 166 */ 167 for (row = 0; row <= ToLines; ++row) { 168 int begin = (row > size_y) ? 0 : (size_x + 1); 169 int end = ToCols; 170 NCURSES_CH_T *s; 171 172 if (!(win->_flags & _SUBWIN)) { 173 if (row <= size_y) { 174 if (ToCols != size_x) { 175 s = typeMalloc(NCURSES_CH_T, (unsigned) ToCols + 1); 176 if (s == 0) 177 returnCode(cleanup_lines(new_lines, row)); 178 for (col = 0; col <= ToCols; ++col) { 179 bool valid = (col <= size_x); 180 if_WIDEC({ 181 if (col == ToCols 182 && col < size_x 183 && isWidecBase(win->_line[row].text[col])) { 184 valid = FALSE; 185 } 186 }); 187 s[col] = (valid 188 ? win->_line[row].text[col] 189 : win->_nc_bkgd); 190 } 191 } else { 192 s = win->_line[row].text; 193 } 194 } else { 195 s = typeMalloc(NCURSES_CH_T, (unsigned) ToCols + 1); 196 if (s == 0) 197 returnCode(cleanup_lines(new_lines, row)); 198 for (col = 0; col <= ToCols; ++col) 199 s[col] = win->_nc_bkgd; 200 } 201 } else if (pline != 0 && pline[win->_pary + row].text != 0) { 202 s = &pline[win->_pary + row].text[win->_parx]; 203 } else { 204 s = 0; 205 } 206 207 if_USE_SCROLL_HINTS(new_lines[row].oldindex = row); 208 if (row <= size_y) { 209 new_lines[row].firstchar = win->_line[row].firstchar; 210 new_lines[row].lastchar = win->_line[row].lastchar; 211 } 212 if ((ToCols != size_x) || (row > size_y)) { 213 if (end >= begin) { /* growing */ 214 if (new_lines[row].firstchar < begin) 215 new_lines[row].firstchar = (NCURSES_SIZE_T) begin; 216 } else { /* shrinking */ 217 new_lines[row].firstchar = 0; 218 } 219 new_lines[row].lastchar = (NCURSES_SIZE_T) ToCols; 220 } 221 new_lines[row].text = s; 222 } 223 224 /* 225 * Dispose of unwanted memory. 226 */ 227 if (!(win->_flags & _SUBWIN)) { 228 if (ToCols == size_x) { 229 for (row = ToLines + 1; row <= size_y; row++) { 230 FreeAndNull(win->_line[row].text); 231 } 232 } else { 233 for (row = 0; row <= size_y; row++) { 234 FreeAndNull(win->_line[row].text); 235 } 236 } 237 } 238 239 FreeAndNull(win->_line); 240 win->_line = new_lines; 241 242 /* 243 * Finally, adjust the parameters showing screen size and cursor 244 * position: 245 */ 246 win->_maxx = (NCURSES_SIZE_T) ToCols; 247 win->_maxy = (NCURSES_SIZE_T) ToLines; 248 249 if (win->_regtop > win->_maxy) 250 win->_regtop = win->_maxy; 251 if (win->_regbottom > win->_maxy 252 || win->_regbottom == size_y) 253 win->_regbottom = win->_maxy; 254 255 if (win->_curx > win->_maxx) 256 win->_curx = win->_maxx; 257 if (win->_cury > win->_maxy) 258 win->_cury = win->_maxy; 259 260 /* 261 * Check for subwindows of this one, and readjust pointers to our text, 262 * if needed. 263 */ 264 repair_subwindows(win); 265 266 #ifdef TRACE 267 TR(TRACE_UPDATE, ("...beg (%ld, %ld), max(%ld,%ld), reg(%ld,%ld)", 268 (long) win->_begy, (long) win->_begx, 269 (long) win->_maxy, (long) win->_maxx, 270 (long) win->_regtop, (long) win->_regbottom)); 271 if (USE_TRACEF(TRACE_UPDATE)) { 272 _tracedump("...after:", win); 273 _nc_unlock_global(tracef); 274 } 275 #endif 276 returnCode(OK); 277 } 278