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