1 /**************************************************************************** 2 * Copyright 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: 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 * 35 ****************************************************************************/ 36 37 /* 38 * lib_refresh.c 39 * 40 * The routines wrefresh() and wnoutrefresh(). 41 * 42 */ 43 44 #include <curses.priv.h> 45 46 MODULE_ID("$Id: lib_refresh.c,v 1.46 2020/02/02 23:34:34 tom Exp $") 47 48 NCURSES_EXPORT(int) 49 wrefresh(WINDOW *win) 50 { 51 int code; 52 #if NCURSES_SP_FUNCS 53 SCREEN *SP_PARM = _nc_screen_of(win); 54 #endif 55 56 T((T_CALLED("wrefresh(%p)"), (void *) win)); 57 58 if (win == 0) { 59 code = ERR; 60 } else if (win == CurScreen(SP_PARM)) { 61 CurScreen(SP_PARM)->_clear = TRUE; 62 code = NCURSES_SP_NAME(doupdate) (NCURSES_SP_ARG); 63 } else if ((code = wnoutrefresh(win)) == OK) { 64 if (win->_clear) 65 NewScreen(SP_PARM)->_clear = TRUE; 66 code = NCURSES_SP_NAME(doupdate) (NCURSES_SP_ARG); 67 /* 68 * Reset the clearok() flag in case it was set for the special 69 * case in hardscroll.c (if we don't reset it here, we'll get 2 70 * refreshes because the flag is copied from stdscr to newscr). 71 * Resetting the flag shouldn't do any harm, anyway. 72 */ 73 win->_clear = FALSE; 74 } 75 returnCode(code); 76 } 77 78 NCURSES_EXPORT(int) 79 wnoutrefresh(WINDOW *win) 80 { 81 int limit_x; 82 int src_row, src_col; 83 int begx; 84 int begy; 85 int dst_row, dst_col; 86 #if USE_SCROLL_HINTS 87 bool wide; 88 #endif 89 #if NCURSES_SP_FUNCS 90 SCREEN *SP_PARM = _nc_screen_of(win); 91 #endif 92 93 T((T_CALLED("wnoutrefresh(%p)"), (void *) win)); 94 95 /* 96 * This function will break badly if we try to refresh a pad. 97 */ 98 if ((win == 0) 99 || (win->_flags & _ISPAD)) 100 returnCode(ERR); 101 102 #ifdef TRACE 103 if (USE_TRACEF(TRACE_UPDATE)) { 104 _tracedump("...win", win); 105 _nc_unlock_global(tracef); 106 } 107 #endif /* TRACE */ 108 109 /* put them here so "win == 0" won't break our code */ 110 begx = win->_begx; 111 begy = win->_begy; 112 113 NewScreen(SP_PARM)->_nc_bkgd = win->_nc_bkgd; 114 WINDOW_ATTRS(NewScreen(SP_PARM)) = WINDOW_ATTRS(win); 115 116 /* merge in change information from all subwindows of this window */ 117 wsyncdown(win); 118 119 #if USE_SCROLL_HINTS 120 /* 121 * For pure efficiency, we'd want to transfer scrolling information 122 * from the window to newscr whenever the window is wide enough that 123 * its update will dominate the cost of the update for the horizontal 124 * band of newscr that it occupies. Unfortunately, this threshold 125 * tends to be complex to estimate, and in any case scrolling the 126 * whole band and rewriting the parts outside win's image would look 127 * really ugly. So. What we do is consider the window "wide" if it 128 * either (a) occupies the whole width of newscr, or (b) occupies 129 * all but at most one column on either vertical edge of the screen 130 * (this caters to fussy people who put boxes around full-screen 131 * windows). Note that changing this formula will not break any code, 132 * merely change the costs of various update cases. 133 */ 134 wide = (begx <= 1 && win->_maxx >= (NewScreen(SP_PARM)->_maxx - 1)); 135 #endif 136 137 win->_flags &= ~_HASMOVED; 138 139 /* 140 * Microtweaking alert! This double loop is one of the genuine 141 * hot spots in the code. Even gcc doesn't seem to do enough 142 * common-subexpression chunking to make it really tense, 143 * so we'll force the issue. 144 */ 145 146 /* limit(dst_col) */ 147 limit_x = win->_maxx; 148 /* limit(src_col) */ 149 if (limit_x > NewScreen(SP_PARM)->_maxx - begx) 150 limit_x = NewScreen(SP_PARM)->_maxx - begx; 151 152 for (src_row = 0, dst_row = begy + win->_yoffset; 153 src_row <= win->_maxy && dst_row <= NewScreen(SP_PARM)->_maxy; 154 src_row++, dst_row++) { 155 struct ldat *nline = &(NewScreen(SP_PARM)->_line[dst_row]); 156 struct ldat *oline = &win->_line[src_row]; 157 158 if (oline->firstchar != _NOCHANGE) { 159 int last_src = oline->lastchar; 160 161 if (last_src > limit_x) 162 last_src = limit_x; 163 164 src_col = oline->firstchar; 165 dst_col = src_col + begx; 166 167 if_WIDEC({ 168 int j; 169 170 /* 171 * Ensure that we will copy complete multi-column characters 172 * on the left-boundary. 173 */ 174 if (isWidecExt(oline->text[src_col])) { 175 j = 1 + dst_col - WidecExt(oline->text[src_col]); 176 if (j < 0) 177 j = 0; 178 if (dst_col > j) { 179 src_col -= (dst_col - j); 180 dst_col = j; 181 } 182 } 183 184 /* 185 * Ensure that we will copy complete multi-column characters 186 * on the right-boundary. 187 */ 188 j = last_src; 189 if (WidecExt(oline->text[j])) { 190 ++j; 191 while (j <= limit_x) { 192 if (isWidecBase(oline->text[j])) { 193 break; 194 } else { 195 last_src = j; 196 } 197 ++j; 198 } 199 } 200 }); 201 202 if_WIDEC({ 203 static cchar_t blank = BLANK; 204 int last_dst = begx + ((last_src < win->_maxx) 205 ? last_src 206 : win->_maxx); 207 int fix_left = dst_col; 208 int fix_right = last_dst; 209 int j; 210 211 /* 212 * Check for boundary cases where we may overwrite part of a 213 * multi-column character. For those, wipe the remainder of 214 * the character to blanks. 215 */ 216 j = dst_col; 217 if (isWidecExt(nline->text[j])) { 218 /* 219 * On the left, we only care about multi-column characters 220 * that extend into the changed region. 221 */ 222 fix_left = 1 + j - WidecExt(nline->text[j]); 223 if (fix_left < 0) 224 fix_left = 0; /* only if cell is corrupt */ 225 } 226 227 j = last_dst; 228 if (WidecExt(nline->text[j]) != 0) { 229 /* 230 * On the right, any multi-column character is a problem, 231 * unless it happens to be contained in the change, and 232 * ending at the right boundary of the change. The 233 * computation for 'fix_left' accounts for the left-side of 234 * this character. Find the end of the character. 235 */ 236 ++j; 237 while (j <= NewScreen(SP_PARM)->_maxx && 238 isWidecExt(nline->text[j])) { 239 fix_right = j++; 240 } 241 } 242 243 /* 244 * The analysis is simpler if we do the clearing afterwards. 245 * Do that now. 246 */ 247 if (fix_left < dst_col || fix_right > last_dst) { 248 for (j = fix_left; j <= fix_right; ++j) { 249 nline->text[j] = blank; 250 CHANGED_CELL(nline, j); 251 } 252 } 253 }); 254 255 /* 256 * Copy the changed text. 257 */ 258 for (; src_col <= last_src; src_col++, dst_col++) { 259 if (!CharEq(oline->text[src_col], nline->text[dst_col])) { 260 nline->text[dst_col] = oline->text[src_col]; 261 CHANGED_CELL(nline, dst_col); 262 } 263 } 264 265 } 266 #if USE_SCROLL_HINTS 267 if (wide) { 268 int oind = oline->oldindex; 269 270 nline->oldindex = ((oind == _NEWINDEX) 271 ? _NEWINDEX 272 : (begy + oind + win->_yoffset)); 273 } 274 #endif /* USE_SCROLL_HINTS */ 275 276 oline->firstchar = oline->lastchar = _NOCHANGE; 277 if_USE_SCROLL_HINTS(oline->oldindex = src_row); 278 } 279 280 if (win->_clear) { 281 win->_clear = FALSE; 282 NewScreen(SP_PARM)->_clear = TRUE; 283 } 284 285 if (!win->_leaveok) { 286 NewScreen(SP_PARM)->_cury = (NCURSES_SIZE_T) (win->_cury + 287 win->_begy + win->_yoffset); 288 NewScreen(SP_PARM)->_curx = (NCURSES_SIZE_T) (win->_curx + win->_begx); 289 } 290 NewScreen(SP_PARM)->_leaveok = win->_leaveok; 291 292 #ifdef TRACE 293 if (USE_TRACEF(TRACE_UPDATE)) { 294 _tracedump("newscr", NewScreen(SP_PARM)); 295 _nc_unlock_global(tracef); 296 } 297 #endif /* TRACE */ 298 returnCode(OK); 299 } 300