1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
|
From esr@locke.ccil.org Sat Jan 13 18:02 EST 1996
Received: from locke.ccil.org (esr@locke.ccil.org [205.164.136.88]) by mail.Clark.Net (8.7.3/8.6.5) with SMTP id SAA07403 for <dickey@clark.net>; Sat, 13 Jan 1996 18:02:54 -0500 (EST)
Received: (esr@localhost) by locke.ccil.org (8.6.9/8.6.10) id SAA23481; Sat, 13 Jan 1996 18:28:57 -0500
From: "Eric S. Raymond" <esr@locke.ccil.org>
Message-Id: <199601132328.SAA23481@locke.ccil.org>
Subject: patch #283 -- change line-breakout optimization logic
To: zmbenhal@netcom.com, dickey@clark.net, ncurses-list@netcom.com
Date: Sat, 13 Jan 1996 18:28:56 -0500 (EST)
X-Mailer: ELM [version 2.4 PL24]
Content-Type: text
Content-Length: 9395
Status: RO
This patch (#283) changes the logic for line-breakout optimization.
Daniel Barlow complained:
>According to curs_inopts(3), curses periodically looks at the keyboard
>while refreshing, and stops immediately if there is input pending.
>
>This works too well! I was playing with emacs to see if it would like
>to use real ncurses routines to output to the screen instead of just
>using it as a glorified termcap library, and found that if I held down
>the `page down' key (which autorepeats), nothing displayed at all
>until I let go of it again.
This patch addresses the problem. See the comment leading the lib_doupdate.c
patch band for details.
This patch also makes a minor change in lib_initscr() to allow the maximum
escape delay to be set from the environment. Finally, it includes a
workaround for the ncurses 'p' test bug. A real fix is next on my agenda.
Diffs between last version checked in and current workfile(s):
--- NEWS 1996/01/11 19:47:02 1.3
+++ NEWS 1996/01/12 17:10:09
@@ -6,6 +6,8 @@
* fixed broken wsyncup()/wysncdown(), as a result wnoutrefresh() now has
copy-changed-lines behavior.
* added and documented wresize() code.
+* changed the line-breakout optimization code to allow some lines to be
+ emitted before the first check.
### ncurses-1.9.7 -> 1.9.8a
--- ncurses/lib_doupdate.c 1996/01/12 16:09:44 1.6
+++ ncurses/lib_doupdate.c 1996/01/12 16:50:21
@@ -43,6 +43,17 @@
#include "term.h"
/*
+ * 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 6
+
+/*
* 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!
@@ -146,6 +157,26 @@
}
}
+static bool check_pending(void)
+/* check for pending input */
+{
+ if (SP->_checkfd >= 0) {
+ 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)
+ {
+ fflush(SP->_ofp);
+ return OK;
+ }
+ }
+}
+
/*
* No one supports recursive inline functions. However, gcc is quieter if we
* instantiate the recursive part separately.
@@ -278,22 +309,6 @@
SP->_endwin = FALSE;
}
- /* check for pending input */
- if (SP->_checkfd >= 0) {
- 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) {
- fflush(SP->_ofp);
- return OK;
- }
- }
-
/*
* FIXME: Full support for magic-cookie terminals could go in here.
* The theory: we scan the virtual screen looking for attribute
@@ -315,10 +330,15 @@
ClrUpdate(newscr);
newscr->_clear = FALSE;
} else {
+ int changedlines;
+
_nc_scroll_optimize();
T(("Transforming lines"));
- for (i = 0; i < min(screen_lines, newscr->_maxy + 1); i++) {
+ for (i = changedlines = 0;
+ i < min(screen_lines,newscr->_maxy+1);
+ i++)
+ {
/*
* newscr->line[i].firstchar is normally set
* by wnoutrefresh. curscr->line[i].firstchar
@@ -327,17 +347,43 @@
*/
if (newscr->_line[i].firstchar != _NOCHANGE
|| curscr->_line[i].firstchar != _NOCHANGE)
+ {
TransformLine(i);
+ changedlines++;
+ }
+
+ /* mark line changed successfully */
+ if (i <= newscr->_maxy)
+ {
+ newscr->_line[i].firstchar = _NOCHANGE;
+ newscr->_line[i].lastchar = _NOCHANGE;
+ newscr->_line[i].oldindex = i;
+ }
+ if (i <= curscr->_maxy)
+ {
+ curscr->_line[i].firstchar = _NOCHANGE;
+ curscr->_line[i].lastchar = _NOCHANGE;
+ curscr->_line[i].oldindex = i;
+ }
+
+ /*
+ * Here is our line-breakout optimization.
+ */
+ if ((changedlines % CHECK_INTERVAL) == changedlines-1 && check_pending())
+ goto cleanup;
}
}
}
- T(("marking screen as updated"));
- for (i = 0; i <= newscr->_maxy; i++) {
+
+ /* this code won't be executed often */
+ for (i = screen_lines; i <= newscr->_maxy; i++)
+ {
newscr->_line[i].firstchar = _NOCHANGE;
newscr->_line[i].lastchar = _NOCHANGE;
newscr->_line[i].oldindex = i;
}
- for (i = 0; i <= curscr->_maxy; i++) {
+ for (i = screen_lines; i <= curscr->_maxy; i++)
+ {
curscr->_line[i].firstchar = _NOCHANGE;
curscr->_line[i].lastchar = _NOCHANGE;
curscr->_line[i].oldindex = i;
@@ -346,10 +392,11 @@
curscr->_curx = newscr->_curx;
curscr->_cury = newscr->_cury;
+ GoTo(curscr->_cury, curscr->_curx);
+
+ cleanup:
if (curscr->_attrs != A_NORMAL)
vidattr(curscr->_attrs = A_NORMAL);
-
- GoTo(curscr->_cury, curscr->_curx);
fflush(SP->_ofp);
--- ncurses/lib_initscr.c 1996/01/12 20:11:34 1.1
+++ ncurses/lib_initscr.c 1996/01/12 20:17:54
@@ -41,6 +41,10 @@
exit(1);
}
+ /* allow user to set maximum escape delay from the environment */
+ if ((name = getenv("ESCDELAY")))
+ ESCDELAY = atoi(getenv("ESCDELAY"));
+
def_shell_mode();
/* follow the XPG4 requirement to turn echo off at this point */
--- ncurses/lib_pad.c 1995/12/29 15:34:11 1.2
+++ ncurses/lib_pad.c 1996/01/13 17:56:24
@@ -107,6 +107,7 @@
short m, n;
short pmaxrow;
short pmaxcol;
+bool wide;
T(("pnoutrefresh(%p, %d, %d, %d, %d, %d, %d) called",
win, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol));
@@ -140,20 +141,46 @@
T(("pad being refreshed"));
+ /*
+ * 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.
+ */
+ wide = (sminrow <= 1 && win->_maxx >= (newscr->_maxx - 1));
+
for (i = pminrow, m = sminrow; i <= pmaxrow; i++, m++) {
+ register struct ldat *nline = &newscr->_line[m];
+ register struct ldat *oline = &win->_line[i];
+
for (j = pmincol, n = smincol; j <= pmaxcol; j++, n++) {
- if (win->_line[i].text[j] != newscr->_line[m].text[n]) {
- newscr->_line[m].text[n] = win->_line[i].text[j];
+ if (oline->text[j] != nline->text[n]) {
+ nline->text[n] = oline->text[j];
+
+ if (nline->firstchar == _NOCHANGE)
+ nline->firstchar = nline->lastchar = n;
+ else if (n < nline->firstchar)
+ nline->firstchar = n;
+ else if (n > nline->lastchar)
+ nline->lastchar = n;
+ }
+ }
+
+ if (wide) {
+ int oind = oline->oldindex;
- if (newscr->_line[m].firstchar == _NOCHANGE)
- newscr->_line[m].firstchar = newscr->_line[m].lastchar = n;
- else if (n < newscr->_line[m].firstchar)
- newscr->_line[m].firstchar = n;
- else if (n > newscr->_line[m].lastchar)
- newscr->_line[m].lastchar = n;
- }
+ nline->oldindex = (oind == _NEWINDEX) ? _NEWINDEX : sminrow + oind;
}
- win->_line[i].firstchar = win->_line[i].lastchar = _NOCHANGE;
+ oline->firstchar = oline->lastchar = _NOCHANGE;
+ oline->oldindex = i;
}
win->_begx = smincol;
@@ -176,6 +203,7 @@
newscr->_cury = win->_cury - pminrow + win->_begy;
newscr->_curx = win->_curx - pmincol + win->_begx;
}
+ win->_flags &= ~_HASMOVED;
return OK;
}
--- test/ncurses.c 1996/01/11 19:49:39 1.4
+++ test/ncurses.c 1996/01/13 23:00:26
@@ -1368,6 +1368,35 @@
}
mvaddch(porty - 1, portx - 1, ACS_LRCORNER);
+
+ /*
+ * FIXME: this touchwin should not be necessary!
+ * There is something not quite right with the pad code
+ * Thomas Dickey writes:
+ *
+ * In the ncurses 'p' test, if I (now) press '<', '>', '<', then the
+ * right boundary of the box that outlines the pad is blanked. That's
+ * because
+ *
+ * + the value that marks the right boundary (porty) is incremented,
+ *
+ * + a new vertical line is written to stdscr
+ *
+ * + stdscr is flushed with wnoutrefresh, clearing its firstchar &
+ * lastchar markers. This writes the change (the new vertical line)
+ * to newscr.
+ *
+ * => previously stdscr was written to newscr entirely
+ *
+ * + the pad is written using prefresh, which writes directly to
+ * newscr, bypassing stdscr entirely.
+ *
+ * When I've pressed '>' (see above), this means that stdscr contains
+ * two columns of ACS_VLINE characters. The left one (column 79) is
+ * shadowed by the pad that's written to newscr.
+ */
+ touchwin(stdscr);
+
wnoutrefresh(stdscr);
prefresh(pad,
End of diffs.
|