1/**************************************************************************** 2 * Copyright 2020-2021,2023 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 46MODULE_ID("$Id: lib_refresh.c,v 1.48 2023/05/27 20:13:10 tom Exp $") 47 48NCURSES_EXPORT(int) 49wrefresh(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 78NCURSES_EXPORT(int) 79wnoutrefresh(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 if (win == NULL) 96 returnCode(ERR); 97 98 /* 99 * Handle pads as a special case. 100 */ 101 if (IS_PAD(win)) { 102 returnCode(pnoutrefresh(win, 103 win->_pad._pad_y, 104 win->_pad._pad_x, 105 win->_pad._pad_top, 106 win->_pad._pad_left, 107 win->_pad._pad_bottom, 108 win->_pad._pad_right)); 109 } 110#ifdef TRACE 111 if (USE_TRACEF(TRACE_UPDATE)) { 112 _tracedump("...win", win); 113 _nc_unlock_global(tracef); 114 } 115#endif /* TRACE */ 116 117 /* put them here so "win == 0" won't break our code */ 118 begx = win->_begx; 119 begy = win->_begy; 120 121 NewScreen(SP_PARM)->_nc_bkgd = win->_nc_bkgd; 122 WINDOW_ATTRS(NewScreen(SP_PARM)) = WINDOW_ATTRS(win); 123 124 /* merge in change information from all subwindows of this window */ 125 wsyncdown(win); 126 127#if USE_SCROLL_HINTS 128 /* 129 * For pure efficiency, we'd want to transfer scrolling information 130 * from the window to newscr whenever the window is wide enough that 131 * its update will dominate the cost of the update for the horizontal 132 * band of newscr that it occupies. Unfortunately, this threshold 133 * tends to be complex to estimate, and in any case scrolling the 134 * whole band and rewriting the parts outside win's image would look 135 * really ugly. So. What we do is consider the window "wide" if it 136 * either (a) occupies the whole width of newscr, or (b) occupies 137 * all but at most one column on either vertical edge of the screen 138 * (this caters to fussy people who put boxes around full-screen 139 * windows). Note that changing this formula will not break any code, 140 * merely change the costs of various update cases. 141 */ 142 wide = (begx <= 1 && win->_maxx >= (NewScreen(SP_PARM)->_maxx - 1)); 143#endif 144 145 win->_flags &= ~_HASMOVED; 146 147 /* 148 * Microtweaking alert! This double loop is one of the genuine 149 * hot spots in the code. Even gcc doesn't seem to do enough 150 * common-subexpression chunking to make it really tense, 151 * so we'll force the issue. 152 */ 153 154 /* limit(dst_col) */ 155 limit_x = win->_maxx; 156 /* limit(src_col) */ 157 if (limit_x > NewScreen(SP_PARM)->_maxx - begx) 158 limit_x = NewScreen(SP_PARM)->_maxx - begx; 159 160 for (src_row = 0, dst_row = begy + win->_yoffset; 161 src_row <= win->_maxy && dst_row <= NewScreen(SP_PARM)->_maxy; 162 src_row++, dst_row++) { 163 struct ldat *nline = &(NewScreen(SP_PARM)->_line[dst_row]); 164 struct ldat *oline = &win->_line[src_row]; 165 166 if (oline->firstchar != _NOCHANGE) { 167 int last_src = oline->lastchar; 168 169 if (last_src > limit_x) 170 last_src = limit_x; 171 172 src_col = oline->firstchar; 173 dst_col = src_col + begx; 174 175 if_WIDEC({ 176 int j; 177 178 /* 179 * Ensure that we will copy complete multi-column characters 180 * on the left-boundary. 181 */ 182 if (isWidecExt(oline->text[src_col])) { 183 j = 1 + dst_col - WidecExt(oline->text[src_col]); 184 if (j < 0) 185 j = 0; 186 if (dst_col > j) { 187 src_col -= (dst_col - j); 188 dst_col = j; 189 } 190 } 191 192 /* 193 * Ensure that we will copy complete multi-column characters 194 * on the right-boundary. 195 */ 196 j = last_src; 197 if (WidecExt(oline->text[j])) { 198 ++j; 199 while (j <= limit_x) { 200 if (isWidecBase(oline->text[j])) { 201 break; 202 } else { 203 last_src = j; 204 } 205 ++j; 206 } 207 } 208 }); 209 210 if_WIDEC({ 211 int last_dst = begx + ((last_src < win->_maxx) 212 ? last_src 213 : win->_maxx); 214 int fix_left = dst_col; 215 int fix_right = last_dst; 216 int j; 217 218 /* 219 * Check for boundary cases where we may overwrite part of a 220 * multi-column character. For those, wipe the remainder of 221 * the character to blanks. 222 */ 223 j = dst_col; 224 if (isWidecExt(nline->text[j])) { 225 /* 226 * On the left, we only care about multi-column characters 227 * that extend into the changed region. 228 */ 229 fix_left = 1 + j - WidecExt(nline->text[j]); 230 if (fix_left < 0) 231 fix_left = 0; /* only if cell is corrupt */ 232 } 233 234 j = last_dst; 235 if (WidecExt(nline->text[j]) != 0) { 236 /* 237 * On the right, any multi-column character is a problem, 238 * unless it happens to be contained in the change, and 239 * ending at the right boundary of the change. The 240 * computation for 'fix_left' accounts for the left-side of 241 * this character. Find the end of the character. 242 */ 243 ++j; 244 while (j <= NewScreen(SP_PARM)->_maxx && 245 isWidecExt(nline->text[j])) { 246 fix_right = j++; 247 } 248 } 249 250 /* 251 * The analysis is simpler if we do the clearing afterwards. 252 * Do that now. 253 */ 254 if (fix_left < dst_col || fix_right > last_dst) { 255 for (j = fix_left; j <= fix_right; ++j) { 256 static cchar_t blank = BLANK; 257 nline->text[j] = blank; 258 CHANGED_CELL(nline, j); 259 } 260 } 261 }); 262 263 /* 264 * Copy the changed text. 265 */ 266 for (; src_col <= last_src; src_col++, dst_col++) { 267 if (!CharEq(oline->text[src_col], nline->text[dst_col])) { 268 nline->text[dst_col] = oline->text[src_col]; 269 CHANGED_CELL(nline, dst_col); 270 } 271 } 272 273 } 274#if USE_SCROLL_HINTS 275 if (wide) { 276 int oind = oline->oldindex; 277 278 nline->oldindex = ((oind == _NEWINDEX) 279 ? _NEWINDEX 280 : (begy + oind + win->_yoffset)); 281 } 282#endif /* USE_SCROLL_HINTS */ 283 284 oline->firstchar = oline->lastchar = _NOCHANGE; 285 if_USE_SCROLL_HINTS(oline->oldindex = src_row); 286 } 287 288 if (win->_clear) { 289 win->_clear = FALSE; 290 NewScreen(SP_PARM)->_clear = TRUE; 291 } 292 293 if (!win->_leaveok) { 294 NewScreen(SP_PARM)->_cury = (NCURSES_SIZE_T) (win->_cury + 295 win->_begy + win->_yoffset); 296 NewScreen(SP_PARM)->_curx = (NCURSES_SIZE_T) (win->_curx + win->_begx); 297 } 298 NewScreen(SP_PARM)->_leaveok = win->_leaveok; 299 300#ifdef TRACE 301 if (USE_TRACEF(TRACE_UPDATE)) { 302 _tracedump("newscr", NewScreen(SP_PARM)); 303 _nc_unlock_global(tracef); 304 } 305#endif /* TRACE */ 306 returnCode(OK); 307} 308