1 /**************************************************************************** 2 * Copyright 2020 Thomas E. Dickey * 3 * Copyright 1998-2010,2017 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: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 32 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 33 * and: Thomas E. Dickey 1996-on * 34 * and: Juergen Pfeifer 2009 * 35 ****************************************************************************/ 36 37 /* 38 * lib_pad.c 39 * newpad -- create a new pad 40 * pnoutrefresh -- refresh a pad, no update 41 * pechochar -- add a char to a pad and refresh 42 */ 43 44 #include <curses.priv.h> 45 46 MODULE_ID("$Id: lib_pad.c,v 1.48 2020/02/02 23:34:34 tom Exp $") 47 48 NCURSES_EXPORT(WINDOW *) 49 NCURSES_SP_NAME(newpad) (NCURSES_SP_DCLx int l, int c) 50 { 51 WINDOW *win; 52 NCURSES_CH_T *ptr; 53 int i; 54 55 T((T_CALLED("newpad(%p,%d, %d)"), (void *) SP_PARM, l, c)); 56 57 if (l <= 0 || c <= 0) 58 returnWin(0); 59 60 win = NCURSES_SP_NAME(_nc_makenew) (NCURSES_SP_ARGx l, c, 0, 0, _ISPAD); 61 if (win == NULL) 62 returnWin(0); 63 64 for (i = 0; i < l; i++) { 65 if_USE_SCROLL_HINTS(win->_line[i].oldindex = _NEWINDEX); 66 if ((win->_line[i].text = typeCalloc(NCURSES_CH_T, ((size_t) c))) == 0) { 67 (void) _nc_freewin(win); 68 returnWin(0); 69 } 70 for (ptr = win->_line[i].text; ptr < win->_line[i].text + c; ptr++) 71 SetChar(*ptr, BLANK_TEXT, BLANK_ATTR); 72 } 73 74 returnWin(win); 75 } 76 77 #if NCURSES_SP_FUNCS 78 NCURSES_EXPORT(WINDOW *) 79 newpad(int l, int c) 80 { 81 return NCURSES_SP_NAME(newpad) (CURRENT_SCREEN, l, c); 82 } 83 #endif 84 85 NCURSES_EXPORT(WINDOW *) 86 subpad(WINDOW *orig, int l, int c, int begy, int begx) 87 { 88 WINDOW *win = (WINDOW *) 0; 89 90 T((T_CALLED("subpad(%d, %d)"), l, c)); 91 92 if (orig) { 93 if (!(orig->_flags & _ISPAD) 94 || ((win = derwin(orig, l, c, begy, begx)) == NULL)) 95 returnWin(0); 96 } 97 returnWin(win); 98 } 99 100 NCURSES_EXPORT(int) 101 prefresh(WINDOW *win, 102 int pminrow, 103 int pmincol, 104 int sminrow, 105 int smincol, 106 int smaxrow, 107 int smaxcol) 108 { 109 #if NCURSES_SP_FUNCS 110 SCREEN *sp = _nc_screen_of(win); 111 #endif 112 113 T((T_CALLED("prefresh()"))); 114 if (pnoutrefresh(win, pminrow, pmincol, sminrow, smincol, smaxrow, 115 smaxcol) != ERR 116 && NCURSES_SP_NAME(doupdate) (NCURSES_SP_ARG) != ERR) { 117 returnCode(OK); 118 } 119 returnCode(ERR); 120 } 121 122 NCURSES_EXPORT(int) 123 pnoutrefresh(WINDOW *win, 124 int pminrow, 125 int pmincol, 126 int sminrow, 127 int smincol, 128 int smaxrow, 129 int smaxcol) 130 { 131 int i, j; 132 int m, n; 133 int pmaxrow; 134 int pmaxcol; 135 SCREEN *sp; 136 137 #if USE_SCROLL_HINTS 138 const int my_len = 2; /* parameterize the threshold for hardscroll */ 139 NCURSES_SIZE_T displaced; 140 bool wide; 141 #endif 142 143 T((T_CALLED("pnoutrefresh(%p, %d, %d, %d, %d, %d, %d)"), 144 (void *) win, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol)); 145 146 if (win == 0) 147 returnCode(ERR); 148 149 if (!(win->_flags & _ISPAD)) 150 returnCode(ERR); 151 152 sp = _nc_screen_of(win); 153 154 /* negative values are interpreted as zero */ 155 if (pminrow < 0) 156 pminrow = 0; 157 if (pmincol < 0) 158 pmincol = 0; 159 if (sminrow < 0) 160 sminrow = 0; 161 if (smincol < 0) 162 smincol = 0; 163 164 pmaxrow = pminrow + smaxrow - sminrow; 165 pmaxcol = pmincol + smaxcol - smincol; 166 167 T((" pminrow + smaxrow - sminrow %ld, win->_maxy %ld", 168 (long) pmaxrow, (long) win->_maxy)); 169 T((" pmincol + smaxcol - smincol %ld, win->_maxx %ld", 170 (long) pmaxcol, (long) win->_maxx)); 171 172 /* 173 * Trim the caller's screen size back to the actual limits. 174 */ 175 if (pmaxrow > win->_maxy) { 176 smaxrow -= (pmaxrow - win->_maxy); 177 pmaxrow = pminrow + smaxrow - sminrow; 178 } 179 if (pmaxcol > win->_maxx) { 180 smaxcol -= (pmaxcol - win->_maxx); 181 pmaxcol = pmincol + smaxcol - smincol; 182 } 183 184 if (smaxrow >= screen_lines(sp) 185 || smaxcol >= screen_columns(sp) 186 || sminrow > smaxrow 187 || smincol > smaxcol) 188 returnCode(ERR); 189 190 T(("pad being refreshed")); 191 192 #ifdef TRACE 193 if (USE_TRACEF(TRACE_UPDATE)) { 194 _tracedump("...pad", win); 195 _nc_unlock_global(tracef); 196 } 197 #endif /* TRACE */ 198 #if USE_SCROLL_HINTS 199 if (win->_pad._pad_y >= 0) { 200 displaced = pminrow - win->_pad._pad_y 201 - (sminrow - win->_pad._pad_top); 202 T(("pad being shifted by %d line(s)", displaced)); 203 } else 204 displaced = 0; 205 #endif 206 207 /* 208 * For pure efficiency, we'd want to transfer scrolling information 209 * from the pad to newscr whenever the window is wide enough that 210 * its update will dominate the cost of the update for the horizontal 211 * band of newscr that it occupies. Unfortunately, this threshold 212 * tends to be complex to estimate, and in any case scrolling the 213 * whole band and rewriting the parts outside win's image would look 214 * really ugly. So. What we do is consider the pad "wide" if it 215 * either (a) occupies the whole width of newscr, or (b) occupies 216 * all but at most one column on either vertical edge of the screen 217 * (this caters to fussy people who put boxes around full-screen 218 * windows). Note that changing this formula will not break any code, 219 * merely change the costs of various update cases. 220 */ 221 #if USE_SCROLL_HINTS 222 wide = (smincol < my_len && smaxcol > (NewScreen(sp)->_maxx - my_len)); 223 #endif 224 225 for (i = pminrow, m = sminrow + win->_yoffset; 226 i <= pmaxrow && m <= NewScreen(sp)->_maxy; 227 i++, m++) { 228 register struct ldat *nline = &NewScreen(sp)->_line[m]; 229 register struct ldat *oline = &win->_line[i]; 230 for (j = pmincol, n = smincol; j <= pmaxcol; j++, n++) { 231 NCURSES_CH_T ch = oline->text[j]; 232 #if USE_WIDEC_SUPPORT 233 /* 234 * Special case for leftmost character of the displayed area. 235 * Only half of a double-width character may be visible. 236 */ 237 if (j == pmincol 238 && j > 0 239 && isWidecExt(ch)) { 240 SetChar(ch, L(' '), AttrOf(oline->text[j - 1])); 241 } 242 #endif 243 if (!CharEq(ch, nline->text[n])) { 244 nline->text[n] = ch; 245 CHANGED_CELL(nline, n); 246 } 247 } 248 249 #if USE_SCROLL_HINTS 250 if (wide) { 251 int nind = m + displaced; 252 if (oline->oldindex < 0 253 || nind < sminrow 254 || nind > smaxrow) { 255 nind = _NEWINDEX; 256 } else if (displaced) { 257 register struct ldat *pline = &CurScreen(sp)->_line[nind]; 258 for (j = 0; j <= my_len; j++) { 259 int k = NewScreen(sp)->_maxx - j; 260 if (pline->text[j] != nline->text[j] 261 || pline->text[k] != nline->text[k]) { 262 nind = _NEWINDEX; 263 break; 264 } 265 } 266 } 267 268 nline->oldindex = nind; 269 } 270 #endif /* USE_SCROLL_HINTS */ 271 oline->firstchar = oline->lastchar = _NOCHANGE; 272 if_USE_SCROLL_HINTS(oline->oldindex = i); 273 } 274 275 /* 276 * Clean up debris from scrolling or resizing the pad, so we do not 277 * accidentally pick up the index value during the next call to this 278 * procedure. The only rows that should have an index value are those 279 * that are displayed during this cycle. 280 */ 281 #if USE_SCROLL_HINTS 282 for (i = pminrow - 1; (i >= 0) && (win->_line[i].oldindex >= 0); i--) 283 win->_line[i].oldindex = _NEWINDEX; 284 for (i = pmaxrow + 1; (i <= win->_maxy) 285 && (win->_line[i].oldindex >= 0); i++) 286 win->_line[i].oldindex = _NEWINDEX; 287 #endif 288 289 win->_begx = (NCURSES_SIZE_T) smincol; 290 win->_begy = (NCURSES_SIZE_T) sminrow; 291 292 if (win->_clear) { 293 win->_clear = FALSE; 294 NewScreen(sp)->_clear = TRUE; 295 } 296 297 /* 298 * Use the pad's current position, if it will be visible. 299 * If not, don't do anything; it's not an error. 300 */ 301 if (win->_leaveok == FALSE 302 && win->_cury >= pminrow 303 && win->_curx >= pmincol 304 && win->_cury <= pmaxrow 305 && win->_curx <= pmaxcol) { 306 NewScreen(sp)->_cury = (NCURSES_SIZE_T) (win->_cury - pminrow 307 + win->_begy + win->_yoffset); 308 NewScreen(sp)->_curx = (NCURSES_SIZE_T) (win->_curx - pmincol 309 + win->_begx); 310 } 311 NewScreen(sp)->_leaveok = win->_leaveok; 312 win->_flags &= ~_HASMOVED; 313 314 /* 315 * Update our cache of the line-numbers that we displayed from the pad. 316 * We will use this on subsequent calls to this function to derive 317 * values to stuff into 'oldindex[]' -- for scrolling optimization. 318 */ 319 win->_pad._pad_y = (NCURSES_SIZE_T) pminrow; 320 win->_pad._pad_x = (NCURSES_SIZE_T) pmincol; 321 win->_pad._pad_top = (NCURSES_SIZE_T) sminrow; 322 win->_pad._pad_left = (NCURSES_SIZE_T) smincol; 323 win->_pad._pad_bottom = (NCURSES_SIZE_T) smaxrow; 324 win->_pad._pad_right = (NCURSES_SIZE_T) smaxcol; 325 326 returnCode(OK); 327 } 328 329 NCURSES_EXPORT(int) 330 pechochar(WINDOW *pad, const chtype ch) 331 { 332 T((T_CALLED("pechochar(%p, %s)"), (void *) pad, _tracechtype(ch))); 333 334 if (pad == 0) 335 returnCode(ERR); 336 337 if (!(pad->_flags & _ISPAD)) 338 returnCode(wechochar(pad, ch)); 339 340 waddch(pad, ch); 341 prefresh(pad, pad->_pad._pad_y, 342 pad->_pad._pad_x, 343 pad->_pad._pad_top, 344 pad->_pad._pad_left, 345 pad->_pad._pad_bottom, 346 pad->_pad._pad_right); 347 348 returnCode(OK); 349 } 350