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