_tracecchar_t2(int bufnum, const cchar_t *ch) { char *result = _nc_trace_buf(bufnum, BUFSIZ); attr_t attr; const char *found; if (result != 0) { strcpy(result, l_brace); if (ch != 0) { attr = AttrOfD(ch); if ((found = _nc_altcharset_name(attr, (chtype) CharOfD(ch))) != 0) { (void) _nc_trace_bufcat(bufnum, found); attr &= ~A_ALTCHARSET; } else if (isWidecExt(CHDEREF(ch))) { (void) _nc_trace_bufcat(bufnum, "{NAC}"); attr &= ~A_CHARTEXT; } else { PUTC_DATA; int n; PUTC_INIT; (void) _nc_trace_bufcat(bufnum, "{ "); for (PUTC_i = 0; PUTC_i < CCHARW_MAX; ++PUTC_i) { PUTC_ch = ch->chars[PUTC_i]; if (PUTC_ch == L'\0') { if (PUTC_i == 0) result = _nc_trace_bufcat(bufnum, "\\000"); break; } PUTC_n = wcrtomb(PUTC_buf, ch->chars[PUTC_i], &PUT_st); if (PUTC_n <= 0) { if (PUTC_ch != L'\0') { /* it could not be a multibyte sequence */ (void) _nc_trace_bufcat(bufnum, _nc_tracechar(CURRENT_SCREEN, UChar(ch->chars[PUTC_i]))); } break; } for (n = 0; n < PUTC_n; n++) { if (n) (void) _nc_trace_bufcat(bufnum, ", "); (void) _nc_trace_bufcat(bufnum, _nc_tracechar(CURRENT_SCREEN, UChar(PUTC_buf[n]))); } } (void) _nc_trace_bufcat(bufnum, " }"); } if (attr != A_NORMAL) { (void) _nc_trace_bufcat(bufnum, " | "); (void) _nc_trace_bufcat(bufnum, _traceattr2(bufnum + 20, attr)); } } result = _nc_trace_bufcat(bufnum, r_brace); } return result; }
_tracecchar_t2 (int bufnum, const cchar_t *ch) { char *buf = _nc_trace_buf(bufnum, BUFSIZ); attr_t attr; const char *found; strcpy(buf, l_brace); if (ch != 0) { attr = AttrOfD(ch); if ((found = _nc_altcharset_name(attr, CharOfD(ch))) != 0) { (void) _nc_trace_bufcat(bufnum, found); attr &= ~A_ALTCHARSET; } else if (isWidecExt(CHDEREF(ch))) { (void) _nc_trace_bufcat(bufnum, "{NAC}"); attr &= ~A_CHARTEXT; } else { PUTC_DATA; int n; PUTC_INIT; (void) _nc_trace_bufcat(bufnum, "{ "); do { PUTC_ch = PUTC_i < CCHARW_MAX ? ch->chars[PUTC_i] : L'\0'; PUTC_n = wcrtomb(PUTC_buf, ch->chars[PUTC_i], &PUT_st); if (PUTC_ch == L'\0') --PUTC_n; if (PUTC_n <= 0) { if (PUTC_ch != L'\0') { /* it could not be a multibyte sequence */ (void) _nc_trace_bufcat(bufnum, _tracechar(UChar(ch->chars[PUTC_i]))); } break; } for (n = 0; n < PUTC_n; n++) { if (n) (void) _nc_trace_bufcat(bufnum, ", "); (void) _nc_trace_bufcat(bufnum, _tracechar(UChar(PUTC_buf[n]))); } ++PUTC_i; } while (PUTC_ch != L'\0'); (void) _nc_trace_bufcat(bufnum, " }"); } if (attr != A_NORMAL) { (void) _nc_trace_bufcat(bufnum, " | "); (void) _nc_trace_bufcat(bufnum, _traceattr2(bufnum + 20, attr)); } } return (_nc_trace_bufcat(bufnum, r_brace)); }
werase(WINDOW *win) { int code = ERR; NCURSES_CH_T blank; NCURSES_CH_T *start; T((T_CALLED("werase(%p)"), (void *) win)); if (win) { NCURSES_CH_T *sp; int y; blank = win->_nc_bkgd; for (y = 0; y <= win->_maxy; y++) { NCURSES_CH_T *end; start = win->_line[y].text; end = &start[win->_maxx]; /* * If this is a derived window, we have to handle the case where * a multicolumn character extends into the window that we are * erasing. */ if_WIDEC({ if (isWidecExt(start[0])) { int x = (win->_parent != 0) ? (win->_begx) : 0; while (x-- > 0) { if (isWidecBase(start[-1])) { --start; break; } --start; } } }); for (sp = start; sp <= end; sp++) *sp = blank; win->_line[y].firstchar = 0; win->_line[y].lastchar = win->_maxx; } win->_curx = win->_cury = 0; win->_flags &= ~_WRAPPED; _nc_synchook(win); code = OK; }
winnwstr(WINDOW *win, wchar_t *wstr, int n) { int count = 0; cchar_t *text; T((T_CALLED("winnwstr(%p,%p,%d)"), (void *) win, (void *) wstr, n)); if (wstr != 0) { if (win) { int row, col; int last = 0; getyx(win, row, col); text = win->_line[row].text; while (count < n && count != ERR) { if (!isWidecExt(text[col])) { int inx; wchar_t wch; for (inx = 0; (inx < CCHARW_MAX) && ((wch = text[col].chars[inx]) != 0); ++inx) { if (count + 1 > n) { if ((count = last) == 0) { count = ERR; /* error if we store nothing */ } break; } wstr[count++] = wch; } } last = count; if (++col > win->_maxx) { break; } } } if (count > 0) { wstr[count] = '\0'; T(("winnwstr returns %s", _nc_viswbuf(wstr))); } } returnCode(count); }
static int wadd_wch_literal(WINDOW *win, cchar_t ch) { int x; int y; struct ldat *line; x = win->_curx; y = win->_cury; CHECK_POSITION(win, x, y); ch = render_char(win, ch); line = win->_line + y; CHANGED_CELL(line, x); /* * Non-spacing characters are added to the current cell. * * Spacing characters that are wider than one column require some display * adjustments. */ { int len = wcwidth(CharOf(ch)); int i; int j; wchar_t *chars; if (len == 0) { /* non-spacing */ if ((x > 0 && y >= 0) || (win->_maxx >= 0 && win->_cury >= 1)) { if (x > 0 && y >= 0) chars = (win->_line[y].text[x - 1].chars); else chars = (win->_line[y - 1].text[win->_maxx].chars); for (i = 0; i < CCHARW_MAX; ++i) { if (chars[i] == 0) { TR(TRACE_VIRTPUT, ("added non-spacing %d: %x", x, (int) CharOf(ch))); chars[i] = CharOf(ch); break; } } } goto testwrapping; } else if (len > 1) { /* multi-column characters */ /* * Check if the character will fit on the current line. If it does * not fit, fill in the remainder of the line with blanks. and * move to the next line. */ if (len > win->_maxx + 1) { TR(TRACE_VIRTPUT, ("character will not fit")); return ERR; } else if (x + len > win->_maxx + 1) { int count = win->_maxx + 1 - x; TR(TRACE_VIRTPUT, ("fill %d remaining cells", count)); fill_cells(win, count); if (wrap_to_next_line(win) == ERR) return ERR; x = win->_curx; y = win->_cury; line = win->_line + y; } /* * Check for cells which are orphaned by adding this character, set * those to blanks. * * FIXME: this actually could fill j-i cells, more complicated to * setup though. */ for (i = 0; i < len; ++i) { if (isWidecBase(win->_line[y].text[x + i])) { break; } else if (isWidecExt(win->_line[y].text[x + i])) { for (j = i; x + j <= win->_maxx; ++j) { if (!isWidecExt(win->_line[y].text[x + j])) { TR(TRACE_VIRTPUT, ("fill %d orphan cells", j)); fill_cells(win, j); break; } } break; } } /* * Finally, add the cells for this character. */ for (i = 0; i < len; ++i) { cchar_t value = ch; SetWidecExt(value, i); TR(TRACE_VIRTPUT, ("multicolumn %d:%d (%d,%d)", i + 1, len, win->_begy + y, win->_begx + x)); line->text[x] = value; CHANGED_CELL(line, x); ++x; } goto testwrapping; } } /* * Single-column characters. */ line->text[x++] = ch; /* * This label is used only for wide-characters. */ testwrapping: TR(TRACE_VIRTPUT, ("cell (%ld, %ld..%d) = %s", (long) win->_cury, (long) win->_curx, x - 1, _tracech_t(CHREF(ch)))); if (x > win->_maxx) { return wrap_to_next_line(win); } win->_curx = (NCURSES_SIZE_T) x; return OK; }
pnoutrefresh(WINDOW *win, int pminrow, int pmincol, int sminrow, int smincol, int smaxrow, int smaxcol) { NCURSES_SIZE_T i, j; NCURSES_SIZE_T m, n; NCURSES_SIZE_T pmaxrow; NCURSES_SIZE_T pmaxcol; SCREEN *sp; #if USE_SCROLL_HINTS const int my_len = 2; /* parameterize the threshold for hardscroll */ NCURSES_SIZE_T displaced; bool wide; #endif T((T_CALLED("pnoutrefresh(%p, %d, %d, %d, %d, %d, %d)"), (void *) win, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol)); if (win == 0) returnCode(ERR); if (!(win->_flags & _ISPAD)) returnCode(ERR); sp = _nc_screen_of(win); /* negative values are interpreted as zero */ if (pminrow < 0) pminrow = 0; if (pmincol < 0) pmincol = 0; if (sminrow < 0) sminrow = 0; if (smincol < 0) smincol = 0; pmaxrow = pminrow + smaxrow - sminrow; pmaxcol = pmincol + smaxcol - smincol; T((" pminrow + smaxrow - sminrow %ld, win->_maxy %ld", (long) pmaxrow, (long) win->_maxy)); T((" pmincol + smaxcol - smincol %ld, win->_maxx %ld", (long) pmaxcol, (long) win->_maxx)); /* * Trim the caller's screen size back to the actual limits. */ if (pmaxrow > win->_maxy) { smaxrow -= (pmaxrow - win->_maxy); pmaxrow = pminrow + smaxrow - sminrow; } if (pmaxcol > win->_maxx) { smaxcol -= (pmaxcol - win->_maxx); pmaxcol = pmincol + smaxcol - smincol; } if (smaxrow >= screen_lines(sp) || smaxcol >= screen_columns(sp) || sminrow > smaxrow || smincol > smaxcol) returnCode(ERR); T(("pad being refreshed")); #if USE_SCROLL_HINTS if (win->_pad._pad_y >= 0) { displaced = pminrow - win->_pad._pad_y - (sminrow - win->_pad._pad_top); T(("pad being shifted by %d line(s)", displaced)); } else displaced = 0; #endif /* * For pure efficiency, we'd want to transfer scrolling information * from the pad to newscr whenever the window is wide enough that * its update will dominate the cost of the update for the horizontal * band of newscr that it occupies. Unfortunately, this threshold * tends to be complex to estimate, and in any case scrolling the * whole band and rewriting the parts outside win's image would look * really ugly. So. What we do is consider the pad "wide" if it * either (a) occupies the whole width of newscr, or (b) occupies * all but at most one column on either vertical edge of the screen * (this caters to fussy people who put boxes around full-screen * windows). Note that changing this formula will not break any code, * merely change the costs of various update cases. */ #if USE_SCROLL_HINTS wide = (smincol < my_len && smaxcol > (NewScreen(sp)->_maxx - my_len)); #endif for (i = pminrow, m = sminrow + win->_yoffset; i <= pmaxrow && m <= NewScreen(sp)->_maxy; i++, m++) { register struct ldat *nline = &NewScreen(sp)->_line[m]; register struct ldat *oline = &win->_line[i]; for (j = pmincol, n = smincol; j <= pmaxcol; j++, n++) { NCURSES_CH_T ch = oline->text[j]; #if USE_WIDEC_SUPPORT /* * Special case for leftmost character of the displayed area. * Only half of a double-width character may be visible. */ if (j == pmincol && j > 0 && isWidecExt(ch)) { SetChar(ch, L(' '), AttrOf(oline->text[j - 1])); } #endif if (!CharEq(ch, nline->text[n])) { nline->text[n] = ch; CHANGED_CELL(nline, n); } } #if USE_SCROLL_HINTS if (wide) { int nind = m + displaced; if (oline->oldindex < 0 || nind < sminrow || nind > smaxrow) { nind = _NEWINDEX; } else if (displaced) { register struct ldat *pline = &CurScreen(sp)->_line[nind]; for (j = 0; j <= my_len; j++) { int k = NewScreen(sp)->_maxx - j; if (pline->text[j] != nline->text[j] || pline->text[k] != nline->text[k]) { nind = _NEWINDEX; break; } } } nline->oldindex = nind; } #endif /* USE_SCROLL_HINTS */ oline->firstchar = oline->lastchar = _NOCHANGE; if_USE_SCROLL_HINTS(oline->oldindex = i); } /* * Clean up debris from scrolling or resizing the pad, so we do not * accidentally pick up the index value during the next call to this * procedure. The only rows that should have an index value are those * that are displayed during this cycle. */ #if USE_SCROLL_HINTS for (i = pminrow - 1; (i >= 0) && (win->_line[i].oldindex >= 0); i--) win->_line[i].oldindex = _NEWINDEX; for (i = pmaxrow + 1; (i <= win->_maxy) && (win->_line[i].oldindex >= 0); i++) win->_line[i].oldindex = _NEWINDEX; #endif win->_begx = smincol; win->_begy = sminrow; if (win->_clear) { win->_clear = FALSE; NewScreen(sp)->_clear = TRUE; } /* * Use the pad's current position, if it will be visible. * If not, don't do anything; it's not an error. */ if (win->_leaveok == FALSE && win->_cury >= pminrow && win->_curx >= pmincol && win->_cury <= pmaxrow && win->_curx <= pmaxcol) { NewScreen(sp)->_cury = win->_cury - pminrow + win->_begy + win->_yoffset; NewScreen(sp)->_curx = win->_curx - pmincol + win->_begx; } NewScreen(sp)->_leaveok = win->_leaveok; win->_flags &= ~_HASMOVED; /* * Update our cache of the line-numbers that we displayed from the pad. * We will use this on subsequent calls to this function to derive * values to stuff into 'oldindex[]' -- for scrolling optimization. */ win->_pad._pad_y = pminrow; win->_pad._pad_x = pmincol; win->_pad._pad_top = sminrow; win->_pad._pad_left = smincol; win->_pad._pad_bottom = smaxrow; win->_pad._pad_right = smaxcol; returnCode(OK); }
wadd_wchnstr(WINDOW *win, const cchar_t *astr, int n) { NCURSES_CH_T blank = NewChar(BLANK_TEXT); NCURSES_SIZE_T y = win->_cury; NCURSES_SIZE_T x = win->_curx; int code = OK; struct ldat *line; int i, j, start, len, end; T((T_CALLED("wadd_wchnstr(%p,%s,%d)"), win, _nc_viscbuf(astr, n), n)); if (!win) returnCode(ERR); if (n < 0) { n = _nc_wchstrlen(astr); } if (n > win->_maxx - x + 1) n = win->_maxx - x + 1; if (n == 0) returnCode(code); line = &(win->_line[y]); start = x; end = x + n - 1; /* * Reset orphaned cells of multi-column characters that extend up to the * new string's location to blanks. */ if (x > 0 && isWidecExt(line->text[x])) { for (i = 0; i <= x; ++i) { if (!isWidecExt(line->text[x - i])) { /* must be isWidecBase() */ start -= i; while (i > 0) { line->text[x - i--] = _nc_render(win, blank); } break; } } } /* * Copy the new string to the window. */ for (i = 0; i < n && x <= win->_maxx; ++i) { if (isWidecExt(astr[i])) continue; len = wcwidth(CharOf(astr[i])); if (x + len - 1 <= win->_maxx) { line->text[x] = _nc_render(win, astr[i]); if (len > 1) { for (j = 0; j < len; ++j) { if (j != 0) { line->text[x + j] = line->text[x]; } SetWidecExt(line->text[x + j], j); } } x += len; end += len - 1; } else { break; } } /* * Set orphaned cells of multi-column characters which lie after the new * string to blanks. */ while (x <= win->_maxx && isWidecExt(line->text[x])) { line->text[x] = _nc_render(win, blank); ++end; ++x; } CHANGED_RANGE(line, start, end); _nc_synchook(win); returnCode(code); }
wnoutrefresh(WINDOW *win) { int limit_x; int src_row, src_col; int begx; int begy; int dst_row, dst_col; #if USE_SCROLL_HINTS bool wide; #endif #if NCURSES_SP_FUNCS SCREEN *SP_PARM = _nc_screen_of(win); #endif T((T_CALLED("wnoutrefresh(%p)"), (void *) win)); #ifdef TRACE if (USE_TRACEF(TRACE_UPDATE)) { _tracedump("...win", win); _nc_unlock_global(tracef); } #endif /* TRACE */ /* * This function will break badly if we try to refresh a pad. */ if ((win == 0) || (win->_flags & _ISPAD)) returnCode(ERR); /* put them here so "win == 0" won't break our code */ begx = win->_begx; begy = win->_begy; NewScreen(SP_PARM)->_nc_bkgd = win->_nc_bkgd; WINDOW_ATTRS(NewScreen(SP_PARM)) = WINDOW_ATTRS(win); /* merge in change information from all subwindows of this window */ wsyncdown(win); #if USE_SCROLL_HINTS /* * For pure efficiency, we'd want to transfer scrolling information * from the window to newscr whenever the window is wide enough that * its update will dominate the cost of the update for the horizontal * band of newscr that it occupies. Unfortunately, this threshold * tends to be complex to estimate, and in any case scrolling the * whole band and rewriting the parts outside win's image would look * really ugly. So. What we do is consider the window "wide" if it * either (a) occupies the whole width of newscr, or (b) occupies * all but at most one column on either vertical edge of the screen * (this caters to fussy people who put boxes around full-screen * windows). Note that changing this formula will not break any code, * merely change the costs of various update cases. */ wide = (begx <= 1 && win->_maxx >= (NewScreen(SP_PARM)->_maxx - 1)); #endif win->_flags &= ~_HASMOVED; /* * Microtweaking alert! This double loop is one of the genuine * hot spots in the code. Even gcc doesn't seem to do enough * common-subexpression chunking to make it really tense, * so we'll force the issue. */ /* limit(dst_col) */ limit_x = win->_maxx; /* limit(src_col) */ if (limit_x > NewScreen(SP_PARM)->_maxx - begx) limit_x = NewScreen(SP_PARM)->_maxx - begx; for (src_row = 0, dst_row = begy + win->_yoffset; src_row <= win->_maxy && dst_row <= NewScreen(SP_PARM)->_maxy; src_row++, dst_row++) { struct ldat *nline = &(NewScreen(SP_PARM)->_line[dst_row]); struct ldat *oline = &win->_line[src_row]; if (oline->firstchar != _NOCHANGE) { int last_src = oline->lastchar; if (last_src > limit_x) last_src = limit_x; src_col = oline->firstchar; dst_col = src_col + begx; if_WIDEC({ int j; /* * Ensure that we will copy complete multi-column characters * on the left-boundary. */ if (isWidecExt(oline->text[src_col])) { j = 1 + dst_col - WidecExt(oline->text[src_col]); if (j < 0) j = 0; if (dst_col > j) { src_col -= (dst_col - j); dst_col = j; } } /* * Ensure that we will copy complete multi-column characters * on the right-boundary. */ j = last_src; if (WidecExt(oline->text[j])) { ++j; while (j <= limit_x) { if (isWidecBase(oline->text[j])) { break; } else { last_src = j; } ++j; } } }); if_WIDEC({ static cchar_t blank = BLANK; int last_dst = begx + ((last_src < win->_maxx) ? last_src : win->_maxx); int fix_left = dst_col; int fix_right = last_dst; int j; /* * Check for boundary cases where we may overwrite part of a * multi-column character. For those, wipe the remainder of * the character to blanks. */ j = dst_col; if (isWidecExt(nline->text[j])) { /* * On the left, we only care about multi-column characters * that extend into the changed region. */ fix_left = 1 + j - WidecExt(nline->text[j]); if (fix_left < 0) fix_left = 0; /* only if cell is corrupt */ } j = last_dst; if (WidecExt(nline->text[j]) != 0) { /* * On the right, any multi-column character is a problem, * unless it happens to be contained in the change, and * ending at the right boundary of the change. The * computation for 'fix_left' accounts for the left-side of * this character. Find the end of the character. */ ++j; while (j <= NewScreen(SP_PARM)->_maxx && isWidecExt(nline->text[j])) { fix_right = j++; } } /* * The analysis is simpler if we do the clearing afterwards. * Do that now. */ if (fix_left < dst_col || fix_right > last_dst) { for (j = fix_left; j <= fix_right; ++j) { nline->text[j] = blank; CHANGED_CELL(nline, j); } } });
_tracecchar_t2(int bufnum, const cchar_t *ch) { char *result = _nc_trace_buf(bufnum, (size_t) BUFSIZ); if (result != 0) { _nc_STRCPY(result, l_brace, TRACE_BUF_SIZE(bufnum)); if (ch != 0) { const char *found; attr_t attr = AttrOfD(ch); if ((found = _nc_altcharset_name(attr, (chtype) CharOfD(ch))) != 0) { (void) _nc_trace_bufcat(bufnum, found); attr &= ~A_ALTCHARSET; } else if (isWidecExt(CHDEREF(ch))) { (void) _nc_trace_bufcat(bufnum, "{NAC}"); attr &= ~A_CHARTEXT; } else { PUTC_DATA; int n; (void) _nc_trace_bufcat(bufnum, "{ "); for (PUTC_i = 0; PUTC_i < CCHARW_MAX; ++PUTC_i) { PUTC_ch = ch->chars[PUTC_i]; if (PUTC_ch == L'\0') { if (PUTC_i == 0) (void) _nc_trace_bufcat(bufnum, "\\000"); break; } PUTC_INIT; PUTC_n = (int) wcrtomb(PUTC_buf, ch->chars[PUTC_i], &PUT_st); if (PUTC_n <= 0) { if (PUTC_ch != L'\0') { /* it could not be a multibyte sequence */ (void) _nc_trace_bufcat(bufnum, _nc_tracechar(CURRENT_SCREEN, UChar(ch->chars[PUTC_i]))); } break; } else if (ch->chars[PUTC_i] > 255) { char temp[80]; _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp)) "{%d:\\u%lx}", wcwidth(ch->chars[PUTC_i]), (unsigned long) ch->chars[PUTC_i]); (void) _nc_trace_bufcat(bufnum, temp); break; } for (n = 0; n < PUTC_n; n++) { if (n) (void) _nc_trace_bufcat(bufnum, ", "); (void) _nc_trace_bufcat(bufnum, _nc_tracechar(CURRENT_SCREEN, UChar(PUTC_buf[n]))); } } (void) _nc_trace_bufcat(bufnum, " }"); } if (attr != A_NORMAL) { (void) _nc_trace_bufcat(bufnum, " | "); (void) _nc_trace_bufcat(bufnum, _traceattr2(bufnum + 20, attr)); } #if NCURSES_EXT_COLORS /* * Just in case the extended color is different from the chtype * value, trace both. */ if (ch->ext_color != PairNumber(attr)) { char temp[80]; _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp)) " X_COLOR{%d:%d}", ch->ext_color, PairNumber(attr)); (void) _nc_trace_bufcat(bufnum, temp); } #endif } result = _nc_trace_bufcat(bufnum, r_brace); } return result; }