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