📄 tty_update.c
字号:
/**************************************************************************** * Copyright (c) 1998-2004,2005 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, distribute with modifications, sublicense, and/or sell * * copies of the Software, and to permit persons to whom the Software is * * furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included * * in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * * Except as contained in this notice, the name(s) of the above copyright * * holders shall not be used in advertising or otherwise to promote the * * sale, use or other dealings in this Software without prior written * * authorization. * ****************************************************************************//**************************************************************************** * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * * and: Eric S. Raymond <esr@snark.thyrsus.com> * * and: Thomas E. Dickey 1996-on * ****************************************************************************//*----------------------------------------------------------------- * * lib_doupdate.c * * The routine doupdate() and its dependents. * All physical output is concentrated here (except _nc_outch() * in lib_tputs.c). * *-----------------------------------------------------------------*/#include <curses.priv.h>#ifdef __BEOS__#undef false#undef true#include <OS.h>#endif#if defined(TRACE) && HAVE_SYS_TIMES_H && HAVE_TIMES#define USE_TRACE_TIMES 1#else#define USE_TRACE_TIMES 0#endif#if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT#include <sys/time.h>#endif#if USE_TRACE_TIMES#include <sys/times.h>#endif#if USE_FUNC_POLL#elif HAVE_SELECT#if HAVE_SYS_SELECT_H#include <sys/select.h>#endif#endif#include <ctype.h>#include <term.h>MODULE_ID("$Id: tty_update.c,v 1.220 2005/08/13 17:12:32 tom Exp $")/* * This define controls the line-breakout optimization. Every once in a * while during screen refresh, we want to check for input and abort the * update if there's some waiting. CHECK_INTERVAL controls the number of * changed lines to be emitted between input checks. * * Note: Input-check-and-abort is no longer done if the screen is being * updated from scratch. This is a feature, not a bug. */#define CHECK_INTERVAL 5#define FILL_BCE() (SP->_coloron && !SP->_default_color && !back_color_erase)static const NCURSES_CH_T normal = NewChar2(BLANK_TEXT, BLANK_ATTR);/* * Enable checking to see if doupdate and friends are tracking the true * cursor position correctly. NOTE: this is a debugging hack which will * work ONLY on ANSI-compatible terminals! *//* #define POSITION_DEBUG */static inline NCURSES_CH_T ClrBlank(WINDOW *win);static int ClrBottom(int total);static void ClearScreen(NCURSES_CH_T blank);static void ClrUpdate(void);static void DelChar(int count);static void InsStr(NCURSES_CH_T * line, int count);static void TransformLine(int const lineno);#ifdef POSITION_DEBUG/**************************************************************************** * * Debugging code. Only works on ANSI-standard terminals. * ****************************************************************************/static voidposition_check(int expected_y, int expected_x, char *legend)/* check to see if the real cursor position matches the virtual */{ char buf[20]; char *s; int y, x; if (!_nc_tracing || (expected_y < 0 && expected_x < 0)) return; _nc_flush(); memset(buf, '\0', sizeof(buf)); putp("\033[6n"); /* only works on ANSI-compatibles */ _nc_flush(); *(s = buf) = 0; do { int ask = sizeof(buf) - 1 - (s - buf); int got = read(0, s, ask); if (got == 0) break; s += got; } while (strchr(buf, 'R') == 0); _tracef("probe returned %s", _nc_visbuf(buf)); /* try to interpret as a position report */ if (sscanf(buf, "\033[%d;%dR", &y, &x) != 2) { _tracef("position probe failed in %s", legend); } else { if (expected_x < 0) expected_x = x - 1; if (expected_y < 0) expected_y = y - 1; if (y - 1 != expected_y || x - 1 != expected_x) { beep(); tputs(tparm("\033[%d;%dH", expected_y + 1, expected_x + 1), 1, _nc_outch); _tracef("position seen (%d, %d) doesn't match expected one (%d, %d) in %s", y - 1, x - 1, expected_y, expected_x, legend); } else { _tracef("position matches OK in %s", legend); } }}#else#define position_check(expected_y, expected_x, legend) /* nothing */#endif /* POSITION_DEBUG *//**************************************************************************** * * Optimized update code * ****************************************************************************/static inline voidGoTo(int const row, int const col){ TR(TRACE_MOVE, ("GoTo(%d, %d) from (%d, %d)", row, col, SP->_cursrow, SP->_curscol)); position_check(SP->_cursrow, SP->_curscol, "GoTo"); mvcur(SP->_cursrow, SP->_curscol, row, col); position_check(SP->_cursrow, SP->_curscol, "GoTo2");}static inline voidPutAttrChar(CARG_CH_T ch){ int chlen = 1; NCURSES_CH_T my_ch; PUTC_DATA; NCURSES_CH_T tilde; NCURSES_CH_T attr = CHDEREF(ch); TR(TRACE_CHARPUT, ("PutAttrChar(%s) at (%d, %d)", _tracech_t(ch), SP->_cursrow, SP->_curscol));#if USE_WIDEC_SUPPORT /* * If this is not a valid character, there is nothing more to do. */ if (isWidecExt(CHDEREF(ch))) { TR(TRACE_CHARPUT, ("...skip")); return; } /* * Determine the number of character cells which the 'ch' value will use * on the screen. It should be at least one. */ if ((chlen = wcwidth(CharOf(CHDEREF(ch)))) <= 0) { static NCURSES_CH_T blank = NewChar(BLANK_TEXT); if (is8bits(CharOf(CHDEREF(ch))) && (isprint(CharOf(CHDEREF(ch))) || (SP->_legacy_coding && CharOf(CHDEREF(ch)) >= 160))) { ; } else { ch = CHREF(blank); TR(TRACE_CHARPUT, ("forced to blank")); } chlen = 1; }#endif if ((AttrOf(attr) & A_ALTCHARSET) && SP->_acs_map != 0 && CharOfD(ch) < ACS_LEN) { my_ch = CHDEREF(ch); /* work around const param */#if USE_WIDEC_SUPPORT /* * This is crude & ugly, but works most of the time. It checks if the * acs_chars string specified that we have a mapping for this * character, and uses the wide-character mapping when we expect the * normal one to be broken (by mis-design ;-). */ if (SP->_screen_acs_fix && SP->_screen_acs_map[CharOf(my_ch)]) { RemAttr(attr, A_ALTCHARSET); my_ch = _nc_wacs[CharOf(my_ch)]; }#endif /* * If we (still) have alternate character set, it is the normal 8bit * flavor. The _screen_acs_map[] array tells if the character was * really in acs_chars, needed because of the way wide/normal line * drawing flavors are integrated. */ if (AttrOf(attr) & A_ALTCHARSET) { int j = CharOfD(ch); chtype temp = UChar(SP->_acs_map[j]); if (!(SP->_screen_acs_map[j])) RemAttr(attr, A_ALTCHARSET); if (temp != 0) SetChar(my_ch, temp, AttrOf(attr)); } ch = CHREF(my_ch); } if (tilde_glitch && (CharOfD(ch) == L('~'))) { SetChar(tilde, L('`'), AttrOf(attr)); ch = CHREF(tilde); } UpdateAttrs(attr);#if !USE_WIDEC_SUPPORT /* FIXME - we do this special case for signal handling, should see how to * make it work for wide characters. */ if (SP->_outch != 0) { SP->_outch(UChar(ch)); } else#endif { PUTC(CHDEREF(ch), SP->_ofp); /* macro's fastest... */ TRACE_OUTCHARS(1); } SP->_curscol += chlen; if (char_padding) { TPUTS_TRACE("char_padding"); putp(char_padding); }}static boolcheck_pending(void)/* check for pending input */{ bool have_pending = FALSE; /* * Only carry out this check when the flag is zero, otherwise we'll * have the refreshing slow down drastically (or stop) if there's an * unread character available. */ if (SP->_fifohold != 0) return FALSE; if (SP->_checkfd >= 0) {#if USE_FUNC_POLL struct pollfd fds[1]; fds[0].fd = SP->_checkfd; fds[0].events = POLLIN; if (poll(fds, 1, 0) > 0) { have_pending = TRUE; }#elif defined(__BEOS__) /* * BeOS's select() is declared in socket.h, so the configure script does * not see it. That's just as well, since that function works only for * sockets. This (using snooze and ioctl) was distilled from Be's patch * for ncurses which uses a separate thread to simulate select(). * * FIXME: the return values from the ioctl aren't very clear if we get * interrupted. */ int n = 0; int howmany = ioctl(0, 'ichr', &n); if (howmany >= 0 && n > 0) { have_pending = TRUE; }#elif HAVE_SELECT fd_set fdset; struct timeval ktimeout; ktimeout.tv_sec = ktimeout.tv_usec = 0; FD_ZERO(&fdset); FD_SET(SP->_checkfd, &fdset); if (select(SP->_checkfd + 1, &fdset, NULL, NULL, &ktimeout) != 0) { have_pending = TRUE; }#endif } if (have_pending) { SP->_fifohold = 5; _nc_flush(); } return FALSE;}/* put char at lower right corner */static voidPutCharLR(const ARG_CH_T ch){ if (!auto_right_margin) { /* we can put the char directly */ PutAttrChar(ch); } else if (enter_am_mode && exit_am_mode) { /* we can suppress automargin */ TPUTS_TRACE("exit_am_mode"); putp(exit_am_mode); PutAttrChar(ch); SP->_curscol--; position_check(SP->_cursrow, SP->_curscol, "exit_am_mode"); TPUTS_TRACE("enter_am_mode"); putp(enter_am_mode); } else if ((enter_insert_mode && exit_insert_mode) || insert_character || parm_ich) { GoTo(screen_lines - 1, screen_columns - 2); PutAttrChar(ch); GoTo(screen_lines - 1, screen_columns - 2); InsStr(newscr->_line[screen_lines - 1].text + screen_columns - 2, 1); }}static voidwrap_cursor(void){ if (eat_newline_glitch) { /* * xenl can manifest two different ways. The vt100 * way is that, when you'd expect the cursor to wrap, * it stays hung at the right margin (on top of the * character just emitted) and doesn't wrap until the * *next* graphic char is emitted. The c100 way is * to ignore LF received just after an am wrap. * * An aggressive way to handle this would be to * emit CR/LF after the char and then assume the wrap * is done, you're on the first position of the next * line, and the terminal out of its weird state. * Here it's safe to just tell the code that the * cursor is in hyperspace and let the next mvcur() * call straighten things out. */ SP->_curscol = -1; SP->_cursrow = -1; } else if (auto_right_margin) { SP->_curscol = 0; SP->_cursrow++; } else { SP->_curscol--; } position_check(SP->_cursrow, SP->_curscol, "wrap_cursor");}static inline voidPutChar(const ARG_CH_T ch)/* insert character, handling automargin stuff */{ if (SP->_cursrow == screen_lines - 1 && SP->_curscol == screen_columns - 1) PutCharLR(ch); else PutAttrChar(ch); if (SP->_curscol >= screen_columns) wrap_cursor(); position_check(SP->_cursrow, SP->_curscol, "PutChar");}/* * Check whether the given character can be output by clearing commands. This * includes test for being a space and not including any 'bad' attributes, such * as A_REVERSE. All attribute flags which don't affect appearance of a space * or can be output by clearing (A_COLOR in case of bce-terminal) are excluded. */static inline boolcan_clear_with(ARG_CH_T ch){ if (!back_color_erase && SP->_coloron) {#if NCURSES_EXT_FUNCS int pair; if (!SP->_default_color) return FALSE; if (SP->_default_fg != C_MASK || SP->_default_bg != C_MASK) return FALSE; if ((pair = GetPair(CHDEREF(ch))) != 0) { short fg, bg; pair_content(pair, &fg, &bg); if (fg != C_MASK || bg != C_MASK) return FALSE; }#else if (AttrOfD(ch) & A_COLOR) return FALSE;#endif } return (ISBLANK(CHDEREF(ch)) && (AttrOfD(ch) & ~(NONBLANK_ATTR | A_COLOR)) == BLANK_ATTR);}/* * Issue a given span of characters from an array. * Must be functionally equivalent to: * for (i = 0; i < num; i++) * PutChar(ntext[i]); * but can leave the cursor positioned at the middle of the interval. * * Returns: 0 - cursor is at the end of interval * 1 - cursor is somewhere in the middle * * This code is optimized using ech and rep. */static intEmitRange(const NCURSES_CH_T * ntext, int num){ int i; if (erase_chars || repeat_char) { while (num > 0) { int runcount; NCURSES_CH_T ntext0; while (num > 1 && !CharEq(ntext[0], ntext[1])) { PutChar(CHREF(ntext[0])); ntext++; num--; } ntext0 = ntext[0]; if (num == 1) { PutChar(CHREF(ntext0)); return 0; } runcount = 2; while (runcount < num && CharEq(ntext[runcount], ntext0)) runcount++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -