1 |
|
|
/* $OpenBSD: tty_update.c,v 1.16 2010/01/12 23:22:07 nicm Exp $ */ |
2 |
|
|
|
3 |
|
|
/**************************************************************************** |
4 |
|
|
* Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * |
5 |
|
|
* * |
6 |
|
|
* Permission is hereby granted, free of charge, to any person obtaining a * |
7 |
|
|
* copy of this software and associated documentation files (the * |
8 |
|
|
* "Software"), to deal in the Software without restriction, including * |
9 |
|
|
* without limitation the rights to use, copy, modify, merge, publish, * |
10 |
|
|
* distribute, distribute with modifications, sublicense, and/or sell * |
11 |
|
|
* copies of the Software, and to permit persons to whom the Software is * |
12 |
|
|
* furnished to do so, subject to the following conditions: * |
13 |
|
|
* * |
14 |
|
|
* The above copyright notice and this permission notice shall be included * |
15 |
|
|
* in all copies or substantial portions of the Software. * |
16 |
|
|
* * |
17 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * |
18 |
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * |
19 |
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * |
20 |
|
|
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * |
21 |
|
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * |
22 |
|
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * |
23 |
|
|
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. * |
24 |
|
|
* * |
25 |
|
|
* Except as contained in this notice, the name(s) of the above copyright * |
26 |
|
|
* holders shall not be used in advertising or otherwise to promote the * |
27 |
|
|
* sale, use or other dealings in this Software without prior written * |
28 |
|
|
* authorization. * |
29 |
|
|
****************************************************************************/ |
30 |
|
|
|
31 |
|
|
/**************************************************************************** |
32 |
|
|
* Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * |
33 |
|
|
* and: Eric S. Raymond <esr@snark.thyrsus.com> * |
34 |
|
|
* and: Thomas E. Dickey 1996-on * |
35 |
|
|
****************************************************************************/ |
36 |
|
|
|
37 |
|
|
/*----------------------------------------------------------------- |
38 |
|
|
* |
39 |
|
|
* lib_doupdate.c |
40 |
|
|
* |
41 |
|
|
* The routine doupdate() and its dependents. |
42 |
|
|
* All physical output is concentrated here (except _nc_outch() |
43 |
|
|
* in lib_tputs.c). |
44 |
|
|
* |
45 |
|
|
*-----------------------------------------------------------------*/ |
46 |
|
|
|
47 |
|
|
#include <curses.priv.h> |
48 |
|
|
|
49 |
|
|
#if defined __HAIKU__ && defined __BEOS__ |
50 |
|
|
#undef __BEOS__ |
51 |
|
|
#endif |
52 |
|
|
|
53 |
|
|
#ifdef __BEOS__ |
54 |
|
|
#undef false |
55 |
|
|
#undef true |
56 |
|
|
#include <OS.h> |
57 |
|
|
#endif |
58 |
|
|
|
59 |
|
|
#if defined(TRACE) && HAVE_SYS_TIMES_H && HAVE_TIMES |
60 |
|
|
#define USE_TRACE_TIMES 1 |
61 |
|
|
#else |
62 |
|
|
#define USE_TRACE_TIMES 0 |
63 |
|
|
#endif |
64 |
|
|
|
65 |
|
|
#if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT |
66 |
|
|
#include <sys/time.h> |
67 |
|
|
#endif |
68 |
|
|
|
69 |
|
|
#if USE_TRACE_TIMES |
70 |
|
|
#include <sys/times.h> |
71 |
|
|
#endif |
72 |
|
|
|
73 |
|
|
#if USE_FUNC_POLL |
74 |
|
|
#elif HAVE_SELECT |
75 |
|
|
#if HAVE_SYS_SELECT_H |
76 |
|
|
#include <sys/select.h> |
77 |
|
|
#endif |
78 |
|
|
#endif |
79 |
|
|
|
80 |
|
|
#include <ctype.h> |
81 |
|
|
#include <term.h> |
82 |
|
|
|
83 |
|
|
MODULE_ID("$Id: tty_update.c,v 1.16 2010/01/12 23:22:07 nicm Exp $") |
84 |
|
|
|
85 |
|
|
/* |
86 |
|
|
* This define controls the line-breakout optimization. Every once in a |
87 |
|
|
* while during screen refresh, we want to check for input and abort the |
88 |
|
|
* update if there's some waiting. CHECK_INTERVAL controls the number of |
89 |
|
|
* changed lines to be emitted between input checks. |
90 |
|
|
* |
91 |
|
|
* Note: Input-check-and-abort is no longer done if the screen is being |
92 |
|
|
* updated from scratch. This is a feature, not a bug. |
93 |
|
|
*/ |
94 |
|
|
#define CHECK_INTERVAL 5 |
95 |
|
|
|
96 |
|
|
#define FILL_BCE() (SP->_coloron && !SP->_default_color && !back_color_erase) |
97 |
|
|
|
98 |
|
|
static const NCURSES_CH_T blankchar = NewChar(BLANK_TEXT); |
99 |
|
|
static NCURSES_CH_T normal = NewChar(BLANK_TEXT); |
100 |
|
|
|
101 |
|
|
/* |
102 |
|
|
* Enable checking to see if doupdate and friends are tracking the true |
103 |
|
|
* cursor position correctly. NOTE: this is a debugging hack which will |
104 |
|
|
* work ONLY on ANSI-compatible terminals! |
105 |
|
|
*/ |
106 |
|
|
/* #define POSITION_DEBUG */ |
107 |
|
|
|
108 |
|
|
static NCURSES_INLINE NCURSES_CH_T ClrBlank(WINDOW *win); |
109 |
|
|
static int ClrBottom(int total); |
110 |
|
|
static void ClearScreen(NCURSES_CH_T blank); |
111 |
|
|
static void ClrUpdate(void); |
112 |
|
|
static void DelChar(int count); |
113 |
|
|
static void InsStr(NCURSES_CH_T * line, int count); |
114 |
|
|
static void TransformLine(int const lineno); |
115 |
|
|
|
116 |
|
|
#ifdef POSITION_DEBUG |
117 |
|
|
/**************************************************************************** |
118 |
|
|
* |
119 |
|
|
* Debugging code. Only works on ANSI-standard terminals. |
120 |
|
|
* |
121 |
|
|
****************************************************************************/ |
122 |
|
|
|
123 |
|
|
static void |
124 |
|
|
position_check(int expected_y, int expected_x, char *legend) |
125 |
|
|
/* check to see if the real cursor position matches the virtual */ |
126 |
|
|
{ |
127 |
|
|
char buf[20]; |
128 |
|
|
char *s; |
129 |
|
|
int y, x; |
130 |
|
|
|
131 |
|
|
if (!_nc_tracing || (expected_y < 0 && expected_x < 0)) |
132 |
|
|
return; |
133 |
|
|
|
134 |
|
|
_nc_flush(); |
135 |
|
|
memset(buf, '\0', sizeof(buf)); |
136 |
|
|
putp("\033[6n"); /* only works on ANSI-compatibles */ |
137 |
|
|
_nc_flush(); |
138 |
|
|
*(s = buf) = 0; |
139 |
|
|
do { |
140 |
|
|
int ask = sizeof(buf) - 1 - (s - buf); |
141 |
|
|
int got = read(0, s, ask); |
142 |
|
|
if (got == 0) |
143 |
|
|
break; |
144 |
|
|
s += got; |
145 |
|
|
} while (strchr(buf, 'R') == 0); |
146 |
|
|
_tracef("probe returned %s", _nc_visbuf(buf)); |
147 |
|
|
|
148 |
|
|
/* try to interpret as a position report */ |
149 |
|
|
if (sscanf(buf, "\033[%d;%dR", &y, &x) != 2) { |
150 |
|
|
_tracef("position probe failed in %s", legend); |
151 |
|
|
} else { |
152 |
|
|
if (expected_x < 0) |
153 |
|
|
expected_x = x - 1; |
154 |
|
|
if (expected_y < 0) |
155 |
|
|
expected_y = y - 1; |
156 |
|
|
if (y - 1 != expected_y || x - 1 != expected_x) { |
157 |
|
|
beep(); |
158 |
|
|
tputs(tparm("\033[%d;%dH", expected_y + 1, expected_x + 1), 1, _nc_outch); |
159 |
|
|
_tracef("position seen (%d, %d) doesn't match expected one (%d, %d) in %s", |
160 |
|
|
y - 1, x - 1, expected_y, expected_x, legend); |
161 |
|
|
} else { |
162 |
|
|
_tracef("position matches OK in %s", legend); |
163 |
|
|
} |
164 |
|
|
} |
165 |
|
|
} |
166 |
|
|
#else |
167 |
|
|
#define position_check(expected_y, expected_x, legend) /* nothing */ |
168 |
|
|
#endif /* POSITION_DEBUG */ |
169 |
|
|
|
170 |
|
|
/**************************************************************************** |
171 |
|
|
* |
172 |
|
|
* Optimized update code |
173 |
|
|
* |
174 |
|
|
****************************************************************************/ |
175 |
|
|
|
176 |
|
|
static NCURSES_INLINE void |
177 |
|
|
GoTo(int const row, int const col) |
178 |
|
|
{ |
179 |
|
|
TR(TRACE_MOVE, ("GoTo(%d, %d) from (%d, %d)", |
180 |
|
|
row, col, SP->_cursrow, SP->_curscol)); |
181 |
|
|
|
182 |
|
|
position_check(SP->_cursrow, SP->_curscol, "GoTo"); |
183 |
|
|
|
184 |
|
|
mvcur(SP->_cursrow, SP->_curscol, row, col); |
185 |
|
|
position_check(SP->_cursrow, SP->_curscol, "GoTo2"); |
186 |
|
|
} |
187 |
|
|
|
188 |
|
|
static NCURSES_INLINE void |
189 |
|
|
PutAttrChar(CARG_CH_T ch) |
190 |
|
|
{ |
191 |
|
|
int chlen = 1; |
192 |
|
|
NCURSES_CH_T my_ch; |
193 |
|
|
PUTC_DATA; |
194 |
|
|
NCURSES_CH_T tilde; |
195 |
|
|
NCURSES_CH_T attr = CHDEREF(ch); |
196 |
|
|
|
197 |
|
|
TR(TRACE_CHARPUT, ("PutAttrChar(%s) at (%d, %d)", |
198 |
|
|
_tracech_t(ch), |
199 |
|
|
SP->_cursrow, SP->_curscol)); |
200 |
|
|
#if USE_WIDEC_SUPPORT |
201 |
|
|
/* |
202 |
|
|
* If this is not a valid character, there is nothing more to do. |
203 |
|
|
*/ |
204 |
|
|
if (isWidecExt(CHDEREF(ch))) { |
205 |
|
|
TR(TRACE_CHARPUT, ("...skip")); |
206 |
|
|
return; |
207 |
|
|
} |
208 |
|
|
/* |
209 |
|
|
* Determine the number of character cells which the 'ch' value will use |
210 |
|
|
* on the screen. It should be at least one. |
211 |
|
|
*/ |
212 |
|
|
if ((chlen = wcwidth(CharOf(CHDEREF(ch)))) <= 0) { |
213 |
|
|
static const NCURSES_CH_T blank = NewChar(BLANK_TEXT); |
214 |
|
|
|
215 |
|
|
/* |
216 |
|
|
* If the character falls into any of these special cases, do |
217 |
|
|
* not force the result to a blank: |
218 |
|
|
* |
219 |
|
|
* a) it is printable (this works around a bug in wcwidth()). |
220 |
|
|
* b) use_legacy_coding() has been called to modify the treatment |
221 |
|
|
* of codes 128-255. |
222 |
|
|
* c) the acs_map[] has been initialized to allow codes 0-31 |
223 |
|
|
* to be rendered. This supports Linux console's "PC" |
224 |
|
|
* characters. Codes 128-255 are allowed though this is |
225 |
|
|
* not checked. |
226 |
|
|
*/ |
227 |
|
|
if (is8bits(CharOf(CHDEREF(ch))) |
228 |
|
|
&& (isprint(CharOf(CHDEREF(ch))) |
229 |
|
|
|| (SP->_legacy_coding > 0 && CharOf(CHDEREF(ch)) >= 160) |
230 |
|
|
|| (SP->_legacy_coding > 1 && CharOf(CHDEREF(ch)) >= 128) |
231 |
|
|
|| (AttrOf(attr) & A_ALTCHARSET |
232 |
|
|
&& ((CharOfD(ch) < ACS_LEN |
233 |
|
|
&& SP->_acs_map != 0 |
234 |
|
|
&& SP->_acs_map[CharOfD(ch)] != 0) |
235 |
|
|
|| (CharOfD(ch) >= 128))))) { |
236 |
|
|
; |
237 |
|
|
} else { |
238 |
|
|
ch = CHREF(blank); |
239 |
|
|
TR(TRACE_CHARPUT, ("forced to blank")); |
240 |
|
|
} |
241 |
|
|
chlen = 1; |
242 |
|
|
} |
243 |
|
|
#endif |
244 |
|
|
|
245 |
|
|
if ((AttrOf(attr) & A_ALTCHARSET) |
246 |
|
|
&& SP->_acs_map != 0 |
247 |
|
|
&& CharOfD(ch) < ACS_LEN) { |
248 |
|
|
my_ch = CHDEREF(ch); /* work around const param */ |
249 |
|
|
#if USE_WIDEC_SUPPORT |
250 |
|
|
/* |
251 |
|
|
* This is crude & ugly, but works most of the time. It checks if the |
252 |
|
|
* acs_chars string specified that we have a mapping for this |
253 |
|
|
* character, and uses the wide-character mapping when we expect the |
254 |
|
|
* normal one to be broken (by mis-design ;-). |
255 |
|
|
*/ |
256 |
|
|
if (SP->_screen_acs_fix |
257 |
|
|
&& SP->_screen_acs_map[CharOf(my_ch)]) { |
258 |
|
|
RemAttr(attr, A_ALTCHARSET); |
259 |
|
|
my_ch = _nc_wacs[CharOf(my_ch)]; |
260 |
|
|
} |
261 |
|
|
#endif |
262 |
|
|
/* |
263 |
|
|
* If we (still) have alternate character set, it is the normal 8bit |
264 |
|
|
* flavor. The _screen_acs_map[] array tells if the character was |
265 |
|
|
* really in acs_chars, needed because of the way wide/normal line |
266 |
|
|
* drawing flavors are integrated. |
267 |
|
|
*/ |
268 |
|
|
if (AttrOf(attr) & A_ALTCHARSET) { |
269 |
|
|
int j = CharOfD(ch); |
270 |
|
|
chtype temp = UChar(SP->_acs_map[j]); |
271 |
|
|
|
272 |
|
|
if (!(SP->_screen_acs_map[j])) { |
273 |
|
|
RemAttr(attr, A_ALTCHARSET); |
274 |
|
|
if (temp == 0) |
275 |
|
|
temp = ' '; |
276 |
|
|
} |
277 |
|
|
if (temp != 0) |
278 |
|
|
SetChar(my_ch, temp, AttrOf(attr)); |
279 |
|
|
} |
280 |
|
|
ch = CHREF(my_ch); |
281 |
|
|
} |
282 |
|
|
if (tilde_glitch && (CharOfD(ch) == L('~'))) { |
283 |
|
|
SetChar(tilde, L('`'), AttrOf(attr)); |
284 |
|
|
ch = CHREF(tilde); |
285 |
|
|
} |
286 |
|
|
|
287 |
|
|
UpdateAttrs(attr); |
288 |
|
|
#if !USE_WIDEC_SUPPORT |
289 |
|
|
/* FIXME - we do this special case for signal handling, should see how to |
290 |
|
|
* make it work for wide characters. |
291 |
|
|
*/ |
292 |
|
|
if (SP->_outch != 0) { |
293 |
|
|
SP->_outch(UChar(ch)); |
294 |
|
|
} else |
295 |
|
|
#endif |
296 |
|
|
{ |
297 |
|
|
PUTC(CHDEREF(ch), SP->_ofp); /* macro's fastest... */ |
298 |
|
|
COUNT_OUTCHARS(1); |
299 |
|
|
} |
300 |
|
|
SP->_curscol += chlen; |
301 |
|
|
if (char_padding) { |
302 |
|
|
TPUTS_TRACE("char_padding"); |
303 |
|
|
putp(char_padding); |
304 |
|
|
} |
305 |
|
|
} |
306 |
|
|
|
307 |
|
|
static bool |
308 |
|
|
check_pending(void) |
309 |
|
|
/* check for pending input */ |
310 |
|
|
{ |
311 |
|
|
bool have_pending = FALSE; |
312 |
|
|
|
313 |
|
|
/* |
314 |
|
|
* Only carry out this check when the flag is zero, otherwise we'll |
315 |
|
|
* have the refreshing slow down drastically (or stop) if there's an |
316 |
|
|
* unread character available. |
317 |
|
|
*/ |
318 |
|
|
if (SP->_fifohold != 0) |
319 |
|
|
return FALSE; |
320 |
|
|
|
321 |
|
|
if (SP->_checkfd >= 0) { |
322 |
|
|
#if USE_FUNC_POLL |
323 |
|
|
struct pollfd fds[1]; |
324 |
|
|
fds[0].fd = SP->_checkfd; |
325 |
|
|
fds[0].events = POLLIN; |
326 |
|
|
if (poll(fds, 1, 0) > 0) { |
327 |
|
|
have_pending = TRUE; |
328 |
|
|
} |
329 |
|
|
#elif defined(__BEOS__) |
330 |
|
|
/* |
331 |
|
|
* BeOS's select() is declared in socket.h, so the configure script does |
332 |
|
|
* not see it. That's just as well, since that function works only for |
333 |
|
|
* sockets. This (using snooze and ioctl) was distilled from Be's patch |
334 |
|
|
* for ncurses which uses a separate thread to simulate select(). |
335 |
|
|
* |
336 |
|
|
* FIXME: the return values from the ioctl aren't very clear if we get |
337 |
|
|
* interrupted. |
338 |
|
|
*/ |
339 |
|
|
int n = 0; |
340 |
|
|
int howmany = ioctl(0, 'ichr', &n); |
341 |
|
|
if (howmany >= 0 && n > 0) { |
342 |
|
|
have_pending = TRUE; |
343 |
|
|
} |
344 |
|
|
#elif HAVE_SELECT |
345 |
|
|
fd_set fdset; |
346 |
|
|
struct timeval ktimeout; |
347 |
|
|
|
348 |
|
|
ktimeout.tv_sec = |
349 |
|
|
ktimeout.tv_usec = 0; |
350 |
|
|
|
351 |
|
|
FD_ZERO(&fdset); |
352 |
|
|
FD_SET(SP->_checkfd, &fdset); |
353 |
|
|
if (select(SP->_checkfd + 1, &fdset, NULL, NULL, &ktimeout) != 0) { |
354 |
|
|
have_pending = TRUE; |
355 |
|
|
} |
356 |
|
|
#endif |
357 |
|
|
} |
358 |
|
|
if (have_pending) { |
359 |
|
|
SP->_fifohold = 5; |
360 |
|
|
_nc_flush(); |
361 |
|
|
} |
362 |
|
|
return FALSE; |
363 |
|
|
} |
364 |
|
|
|
365 |
|
|
/* put char at lower right corner */ |
366 |
|
|
static void |
367 |
|
|
PutCharLR(const ARG_CH_T ch) |
368 |
|
|
{ |
369 |
|
|
if (!auto_right_margin) { |
370 |
|
|
/* we can put the char directly */ |
371 |
|
|
PutAttrChar(ch); |
372 |
|
|
} else if (enter_am_mode && exit_am_mode) { |
373 |
|
|
/* we can suppress automargin */ |
374 |
|
|
TPUTS_TRACE("exit_am_mode"); |
375 |
|
|
putp(exit_am_mode); |
376 |
|
|
|
377 |
|
|
PutAttrChar(ch); |
378 |
|
|
SP->_curscol--; |
379 |
|
|
position_check(SP->_cursrow, SP->_curscol, "exit_am_mode"); |
380 |
|
|
|
381 |
|
|
TPUTS_TRACE("enter_am_mode"); |
382 |
|
|
putp(enter_am_mode); |
383 |
|
|
} else if ((enter_insert_mode && exit_insert_mode) |
384 |
|
|
|| insert_character || parm_ich) { |
385 |
|
|
GoTo(screen_lines - 1, screen_columns - 2); |
386 |
|
|
PutAttrChar(ch); |
387 |
|
|
GoTo(screen_lines - 1, screen_columns - 2); |
388 |
|
|
InsStr(newscr->_line[screen_lines - 1].text + screen_columns - 2, 1); |
389 |
|
|
} |
390 |
|
|
} |
391 |
|
|
|
392 |
|
|
/* |
393 |
|
|
* Wrap the cursor position, i.e., advance to the beginning of the next line. |
394 |
|
|
*/ |
395 |
|
|
static void |
396 |
|
|
wrap_cursor(void) |
397 |
|
|
{ |
398 |
|
|
if (eat_newline_glitch) { |
399 |
|
|
/* |
400 |
|
|
* xenl can manifest two different ways. The vt100 way is that, when |
401 |
|
|
* you'd expect the cursor to wrap, it stays hung at the right margin |
402 |
|
|
* (on top of the character just emitted) and doesn't wrap until the |
403 |
|
|
* *next* graphic char is emitted. The c100 way is to ignore LF |
404 |
|
|
* received just after an am wrap. |
405 |
|
|
* |
406 |
|
|
* An aggressive way to handle this would be to emit CR/LF after the |
407 |
|
|
* char and then assume the wrap is done, you're on the first position |
408 |
|
|
* of the next line, and the terminal out of its weird state. Here |
409 |
|
|
* it's safe to just tell the code that the cursor is in hyperspace and |
410 |
|
|
* let the next mvcur() call straighten things out. |
411 |
|
|
*/ |
412 |
|
|
SP->_curscol = -1; |
413 |
|
|
SP->_cursrow = -1; |
414 |
|
|
} else if (auto_right_margin) { |
415 |
|
|
SP->_curscol = 0; |
416 |
|
|
SP->_cursrow++; |
417 |
|
|
/* |
418 |
|
|
* We've actually moved - but may have to work around problems with |
419 |
|
|
* video attributes not working. |
420 |
|
|
*/ |
421 |
|
|
if (!move_standout_mode && AttrOf(SCREEN_ATTRS(SP))) { |
422 |
|
|
TR(TRACE_CHARPUT, ("turning off (%#lx) %s before wrapping", |
423 |
|
|
(unsigned long) AttrOf(SCREEN_ATTRS(SP)), |
424 |
|
|
_traceattr(AttrOf(SCREEN_ATTRS(SP))))); |
425 |
|
|
(void) VIDATTR(A_NORMAL, 0); |
426 |
|
|
} |
427 |
|
|
} else { |
428 |
|
|
SP->_curscol--; |
429 |
|
|
} |
430 |
|
|
position_check(SP->_cursrow, SP->_curscol, "wrap_cursor"); |
431 |
|
|
} |
432 |
|
|
|
433 |
|
|
static NCURSES_INLINE void |
434 |
|
|
PutChar(const ARG_CH_T ch) |
435 |
|
|
/* insert character, handling automargin stuff */ |
436 |
|
|
{ |
437 |
|
|
if (SP->_cursrow == screen_lines - 1 && SP->_curscol == screen_columns - 1) |
438 |
|
|
PutCharLR(ch); |
439 |
|
|
else |
440 |
|
|
PutAttrChar(ch); |
441 |
|
|
|
442 |
|
|
if (SP->_curscol >= screen_columns) |
443 |
|
|
wrap_cursor(); |
444 |
|
|
|
445 |
|
|
position_check(SP->_cursrow, SP->_curscol, "PutChar"); |
446 |
|
|
} |
447 |
|
|
|
448 |
|
|
/* |
449 |
|
|
* Check whether the given character can be output by clearing commands. This |
450 |
|
|
* includes test for being a space and not including any 'bad' attributes, such |
451 |
|
|
* as A_REVERSE. All attribute flags which don't affect appearance of a space |
452 |
|
|
* or can be output by clearing (A_COLOR in case of bce-terminal) are excluded. |
453 |
|
|
*/ |
454 |
|
|
static NCURSES_INLINE bool |
455 |
|
|
can_clear_with(ARG_CH_T ch) |
456 |
|
|
{ |
457 |
|
|
if (!back_color_erase && SP->_coloron) { |
458 |
|
|
#if NCURSES_EXT_FUNCS |
459 |
|
|
int pair; |
460 |
|
|
|
461 |
|
|
if (!SP->_default_color) |
462 |
|
|
return FALSE; |
463 |
|
|
if (SP->_default_fg != C_MASK || SP->_default_bg != C_MASK) |
464 |
|
|
return FALSE; |
465 |
|
|
if ((pair = GetPair(CHDEREF(ch))) != 0) { |
466 |
|
|
short fg, bg; |
467 |
|
|
pair_content(pair, &fg, &bg); |
468 |
|
|
if (fg != C_MASK || bg != C_MASK) |
469 |
|
|
return FALSE; |
470 |
|
|
} |
471 |
|
|
#else |
472 |
|
|
if (AttrOfD(ch) & A_COLOR) |
473 |
|
|
return FALSE; |
474 |
|
|
#endif |
475 |
|
|
} |
476 |
|
|
return (ISBLANK(CHDEREF(ch)) && |
477 |
|
|
(AttrOfD(ch) & ~(NONBLANK_ATTR | A_COLOR)) == BLANK_ATTR); |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
/* |
481 |
|
|
* Issue a given span of characters from an array. |
482 |
|
|
* Must be functionally equivalent to: |
483 |
|
|
* for (i = 0; i < num; i++) |
484 |
|
|
* PutChar(ntext[i]); |
485 |
|
|
* but can leave the cursor positioned at the middle of the interval. |
486 |
|
|
* |
487 |
|
|
* Returns: 0 - cursor is at the end of interval |
488 |
|
|
* 1 - cursor is somewhere in the middle |
489 |
|
|
* |
490 |
|
|
* This code is optimized using ech and rep. |
491 |
|
|
*/ |
492 |
|
|
static int |
493 |
|
|
EmitRange(const NCURSES_CH_T * ntext, int num) |
494 |
|
|
{ |
495 |
|
|
int i; |
496 |
|
|
|
497 |
|
|
TR(TRACE_CHARPUT, ("EmitRange %d:%s", num, _nc_viscbuf(ntext, num))); |
498 |
|
|
|
499 |
|
|
if (erase_chars || repeat_char) { |
500 |
|
|
while (num > 0) { |
501 |
|
|
int runcount; |
502 |
|
|
NCURSES_CH_T ntext0; |
503 |
|
|
|
504 |
|
|
while (num > 1 && !CharEq(ntext[0], ntext[1])) { |
505 |
|
|
PutChar(CHREF(ntext[0])); |
506 |
|
|
ntext++; |
507 |
|
|
num--; |
508 |
|
|
} |
509 |
|
|
ntext0 = ntext[0]; |
510 |
|
|
if (num == 1) { |
511 |
|
|
PutChar(CHREF(ntext0)); |
512 |
|
|
return 0; |
513 |
|
|
} |
514 |
|
|
runcount = 2; |
515 |
|
|
|
516 |
|
|
while (runcount < num && CharEq(ntext[runcount], ntext0)) |
517 |
|
|
runcount++; |
518 |
|
|
|
519 |
|
|
/* |
520 |
|
|
* The cost expression in the middle isn't exactly right. |
521 |
|
|
* _cup_ch_cost is an upper bound on the cost for moving to the |
522 |
|
|
* end of the erased area, but not the cost itself (which we |
523 |
|
|
* can't compute without emitting the move). This may result |
524 |
|
|
* in erase_chars not getting used in some situations for |
525 |
|
|
* which it would be marginally advantageous. |
526 |
|
|
*/ |
527 |
|
|
if (erase_chars |
528 |
|
|
&& runcount > SP->_ech_cost + SP->_cup_ch_cost |
529 |
|
|
&& can_clear_with(CHREF(ntext0))) { |
530 |
|
|
UpdateAttrs(ntext0); |
531 |
|
|
putp(TPARM_1(erase_chars, runcount)); |
532 |
|
|
|
533 |
|
|
/* |
534 |
|
|
* If this is the last part of the given interval, |
535 |
|
|
* don't bother moving cursor, since it can be the |
536 |
|
|
* last update on the line. |
537 |
|
|
*/ |
538 |
|
|
if (runcount < num) { |
539 |
|
|
GoTo(SP->_cursrow, SP->_curscol + runcount); |
540 |
|
|
} else { |
541 |
|
|
return 1; /* cursor stays in the middle */ |
542 |
|
|
} |
543 |
|
|
} else if (repeat_char && runcount > SP->_rep_cost) { |
544 |
|
|
bool wrap_possible = (SP->_curscol + runcount >= screen_columns); |
545 |
|
|
int rep_count = runcount; |
546 |
|
|
|
547 |
|
|
if (wrap_possible) |
548 |
|
|
rep_count--; |
549 |
|
|
|
550 |
|
|
UpdateAttrs(ntext0); |
551 |
|
|
tputs(TPARM_2(repeat_char, CharOf(ntext0), rep_count), |
552 |
|
|
rep_count, _nc_outch); |
553 |
|
|
SP->_curscol += rep_count; |
554 |
|
|
|
555 |
|
|
if (wrap_possible) |
556 |
|
|
PutChar(CHREF(ntext0)); |
557 |
|
|
} else { |
558 |
|
|
for (i = 0; i < runcount; i++) |
559 |
|
|
PutChar(CHREF(ntext[i])); |
560 |
|
|
} |
561 |
|
|
ntext += runcount; |
562 |
|
|
num -= runcount; |
563 |
|
|
} |
564 |
|
|
return 0; |
565 |
|
|
} |
566 |
|
|
|
567 |
|
|
for (i = 0; i < num; i++) |
568 |
|
|
PutChar(CHREF(ntext[i])); |
569 |
|
|
return 0; |
570 |
|
|
} |
571 |
|
|
|
572 |
|
|
/* |
573 |
|
|
* Output the line in the given range [first .. last] |
574 |
|
|
* |
575 |
|
|
* If there's a run of identical characters that's long enough to justify |
576 |
|
|
* cursor movement, use that also. |
577 |
|
|
* |
578 |
|
|
* Returns: same as EmitRange |
579 |
|
|
*/ |
580 |
|
|
static int |
581 |
|
|
PutRange(const NCURSES_CH_T * otext, |
582 |
|
|
const NCURSES_CH_T * ntext, |
583 |
|
|
int row, |
584 |
|
|
int first, int last) |
585 |
|
|
{ |
586 |
|
|
int i, j, same; |
587 |
|
|
|
588 |
|
|
TR(TRACE_CHARPUT, ("PutRange(%p, %p, %d, %d, %d)", |
589 |
|
|
otext, ntext, row, first, last)); |
590 |
|
|
|
591 |
|
|
if (otext != ntext |
592 |
|
|
&& (last - first + 1) > SP->_inline_cost) { |
593 |
|
|
for (j = first, same = 0; j <= last; j++) { |
594 |
|
|
if (!same && isWidecExt(otext[j])) |
595 |
|
|
continue; |
596 |
|
|
if (CharEq(otext[j], ntext[j])) { |
597 |
|
|
same++; |
598 |
|
|
} else { |
599 |
|
|
if (same > SP->_inline_cost) { |
600 |
|
|
EmitRange(ntext + first, j - same - first); |
601 |
|
|
GoTo(row, first = j); |
602 |
|
|
} |
603 |
|
|
same = 0; |
604 |
|
|
} |
605 |
|
|
} |
606 |
|
|
i = EmitRange(ntext + first, j - same - first); |
607 |
|
|
/* |
608 |
|
|
* Always return 1 for the next GoTo() after a PutRange() if we found |
609 |
|
|
* identical characters at end of interval |
610 |
|
|
*/ |
611 |
|
|
return (same == 0 ? i : 1); |
612 |
|
|
} |
613 |
|
|
return EmitRange(ntext + first, last - first + 1); |
614 |
|
|
} |
615 |
|
|
|
616 |
|
|
/* leave unbracketed here so 'indent' works */ |
617 |
|
|
#define MARK_NOCHANGE(win,row) \ |
618 |
|
|
win->_line[row].firstchar = _NOCHANGE; \ |
619 |
|
|
win->_line[row].lastchar = _NOCHANGE; \ |
620 |
|
|
if_USE_SCROLL_HINTS(win->_line[row].oldindex = row) |
621 |
|
|
|
622 |
|
|
NCURSES_EXPORT(int) |
623 |
|
|
doupdate(void) |
624 |
|
|
{ |
625 |
|
|
int i; |
626 |
|
|
int nonempty; |
627 |
|
|
#if USE_TRACE_TIMES |
628 |
|
|
struct tms before, after; |
629 |
|
|
#endif /* USE_TRACE_TIMES */ |
630 |
|
|
|
631 |
|
|
T((T_CALLED("doupdate()"))); |
632 |
|
|
|
633 |
|
|
if (curscr == 0 |
634 |
|
|
|| newscr == 0) |
635 |
|
|
returnCode(ERR); |
636 |
|
|
|
637 |
|
|
#ifdef TRACE |
638 |
|
|
if (USE_TRACEF(TRACE_UPDATE)) { |
639 |
|
|
if (curscr->_clear) |
640 |
|
|
_tracef("curscr is clear"); |
641 |
|
|
else |
642 |
|
|
_tracedump("curscr", curscr); |
643 |
|
|
_tracedump("newscr", newscr); |
644 |
|
|
_nc_unlock_global(tracef); |
645 |
|
|
} |
646 |
|
|
#endif /* TRACE */ |
647 |
|
|
|
648 |
|
|
_nc_signal_handler(FALSE); |
649 |
|
|
|
650 |
|
|
if (SP->_fifohold) |
651 |
|
|
SP->_fifohold--; |
652 |
|
|
|
653 |
|
|
#if USE_SIZECHANGE |
654 |
|
|
if (SP->_endwin || _nc_handle_sigwinch(SP)) { |
655 |
|
|
/* |
656 |
|
|
* This is a transparent extension: XSI does not address it, |
657 |
|
|
* and applications need not know that ncurses can do it. |
658 |
|
|
* |
659 |
|
|
* Check if the terminal size has changed while curses was off |
660 |
|
|
* (this can happen in an xterm, for example), and resize the |
661 |
|
|
* ncurses data structures accordingly. |
662 |
|
|
*/ |
663 |
|
|
_nc_update_screensize(SP); |
664 |
|
|
} |
665 |
|
|
#endif |
666 |
|
|
|
667 |
|
|
if (SP->_endwin) { |
668 |
|
|
|
669 |
|
|
T(("coming back from shell mode")); |
670 |
|
|
reset_prog_mode(); |
671 |
|
|
|
672 |
|
|
_nc_mvcur_resume(); |
673 |
|
|
_nc_screen_resume(); |
674 |
|
|
SP->_mouse_resume(SP); |
675 |
|
|
|
676 |
|
|
SP->_endwin = FALSE; |
677 |
|
|
} |
678 |
|
|
#if USE_TRACE_TIMES |
679 |
|
|
/* zero the metering machinery */ |
680 |
|
|
RESET_OUTCHARS(); |
681 |
|
|
(void) times(&before); |
682 |
|
|
#endif /* USE_TRACE_TIMES */ |
683 |
|
|
|
684 |
|
|
/* |
685 |
|
|
* This is the support for magic-cookie terminals. The theory: we scan |
686 |
|
|
* the virtual screen looking for attribute turnons. Where we find one, |
687 |
|
|
* check to make sure it's realizable by seeing if the required number of |
688 |
|
|
* un-attributed blanks are present before and after the attributed range; |
689 |
|
|
* try to shift the range boundaries over blanks (not changing the screen |
690 |
|
|
* display) so this becomes true. If it is, shift the beginning attribute |
691 |
|
|
* change appropriately (the end one, if we've gotten this far, is |
692 |
|
|
* guaranteed room for its cookie). If not, nuke the added attributes out |
693 |
|
|
* of the span. |
694 |
|
|
*/ |
695 |
|
|
#if USE_XMC_SUPPORT |
696 |
|
|
if (magic_cookie_glitch > 0) { |
697 |
|
|
int j, k; |
698 |
|
|
attr_t rattr = A_NORMAL; |
699 |
|
|
|
700 |
|
|
for (i = 0; i < screen_lines; i++) { |
701 |
|
|
for (j = 0; j < screen_columns; j++) { |
702 |
|
|
bool failed = FALSE; |
703 |
|
|
NCURSES_CH_T *thisline = newscr->_line[i].text; |
704 |
|
|
attr_t thisattr = AttrOf(thisline[j]) & SP->_xmc_triggers; |
705 |
|
|
attr_t turnon = thisattr & ~rattr; |
706 |
|
|
|
707 |
|
|
/* is an attribute turned on here? */ |
708 |
|
|
if (turnon == 0) { |
709 |
|
|
rattr = thisattr; |
710 |
|
|
continue; |
711 |
|
|
} |
712 |
|
|
|
713 |
|
|
TR(TRACE_ATTRS, ("At (%d, %d): from %s...", i, j, _traceattr(rattr))); |
714 |
|
|
TR(TRACE_ATTRS, ("...to %s", _traceattr(turnon))); |
715 |
|
|
|
716 |
|
|
/* |
717 |
|
|
* If the attribute change location is a blank with a "safe" |
718 |
|
|
* attribute, undo the attribute turnon. This may ensure |
719 |
|
|
* there's enough room to set the attribute before the first |
720 |
|
|
* non-blank in the run. |
721 |
|
|
*/ |
722 |
|
|
#define SAFE(a) (!((a) & SP->_xmc_triggers)) |
723 |
|
|
if (ISBLANK(thisline[j]) && SAFE(turnon)) { |
724 |
|
|
RemAttr(thisline[j], turnon); |
725 |
|
|
continue; |
726 |
|
|
} |
727 |
|
|
|
728 |
|
|
/* check that there's enough room at start of span */ |
729 |
|
|
for (k = 1; k <= magic_cookie_glitch; k++) { |
730 |
|
|
if (j - k < 0 |
731 |
|
|
|| !ISBLANK(thisline[j - k]) |
732 |
|
|
|| !SAFE(AttrOf(thisline[j - k]))) { |
733 |
|
|
failed = TRUE; |
734 |
|
|
TR(TRACE_ATTRS, ("No room at start in %d,%d%s%s", |
735 |
|
|
i, j - k, |
736 |
|
|
(ISBLANK(thisline[j - k]) |
737 |
|
|
? "" |
738 |
|
|
: ":nonblank"), |
739 |
|
|
(SAFE(AttrOf(thisline[j - k])) |
740 |
|
|
? "" |
741 |
|
|
: ":unsafe"))); |
742 |
|
|
break; |
743 |
|
|
} |
744 |
|
|
} |
745 |
|
|
if (!failed) { |
746 |
|
|
bool end_onscreen = FALSE; |
747 |
|
|
int m, n = j; |
748 |
|
|
|
749 |
|
|
/* find end of span, if it's onscreen */ |
750 |
|
|
for (m = i; m < screen_lines; m++) { |
751 |
|
|
for (; n < screen_columns; n++) { |
752 |
|
|
attr_t testattr = AttrOf(newscr->_line[m].text[n]); |
753 |
|
|
if ((testattr & SP->_xmc_triggers) == rattr) { |
754 |
|
|
end_onscreen = TRUE; |
755 |
|
|
TR(TRACE_ATTRS, |
756 |
|
|
("Range attributed with %s ends at (%d, %d)", |
757 |
|
|
_traceattr(turnon), m, n)); |
758 |
|
|
goto foundit; |
759 |
|
|
} |
760 |
|
|
} |
761 |
|
|
n = 0; |
762 |
|
|
} |
763 |
|
|
TR(TRACE_ATTRS, |
764 |
|
|
("Range attributed with %s ends offscreen", |
765 |
|
|
_traceattr(turnon))); |
766 |
|
|
foundit:; |
767 |
|
|
|
768 |
|
|
if (end_onscreen) { |
769 |
|
|
NCURSES_CH_T *lastline = newscr->_line[m].text; |
770 |
|
|
|
771 |
|
|
/* |
772 |
|
|
* If there are safely-attributed blanks at the end of |
773 |
|
|
* the range, shorten the range. This will help ensure |
774 |
|
|
* that there is enough room at end of span. |
775 |
|
|
*/ |
776 |
|
|
while (n >= 0 |
777 |
|
|
&& ISBLANK(lastline[n]) |
778 |
|
|
&& SAFE(AttrOf(lastline[n]))) { |
779 |
|
|
RemAttr(lastline[n--], turnon); |
780 |
|
|
} |
781 |
|
|
|
782 |
|
|
/* check that there's enough room at end of span */ |
783 |
|
|
for (k = 1; k <= magic_cookie_glitch; k++) { |
784 |
|
|
if (n + k >= screen_columns |
785 |
|
|
|| !ISBLANK(lastline[n + k]) |
786 |
|
|
|| !SAFE(AttrOf(lastline[n + k]))) { |
787 |
|
|
failed = TRUE; |
788 |
|
|
TR(TRACE_ATTRS, |
789 |
|
|
("No room at end in %d,%d%s%s", |
790 |
|
|
i, j - k, |
791 |
|
|
(ISBLANK(lastline[n + k]) |
792 |
|
|
? "" |
793 |
|
|
: ":nonblank"), |
794 |
|
|
(SAFE(AttrOf(lastline[n + k])) |
795 |
|
|
? "" |
796 |
|
|
: ":unsafe"))); |
797 |
|
|
break; |
798 |
|
|
} |
799 |
|
|
} |
800 |
|
|
} |
801 |
|
|
} |
802 |
|
|
|
803 |
|
|
if (failed) { |
804 |
|
|
int p, q = j; |
805 |
|
|
|
806 |
|
|
TR(TRACE_ATTRS, |
807 |
|
|
("Clearing %s beginning at (%d, %d)", |
808 |
|
|
_traceattr(turnon), i, j)); |
809 |
|
|
|
810 |
|
|
/* turn off new attributes over span */ |
811 |
|
|
for (p = i; p < screen_lines; p++) { |
812 |
|
|
for (; q < screen_columns; q++) { |
813 |
|
|
attr_t testattr = AttrOf(newscr->_line[p].text[q]); |
814 |
|
|
if ((testattr & SP->_xmc_triggers) == rattr) |
815 |
|
|
goto foundend; |
816 |
|
|
RemAttr(newscr->_line[p].text[q], turnon); |
817 |
|
|
} |
818 |
|
|
q = 0; |
819 |
|
|
} |
820 |
|
|
foundend:; |
821 |
|
|
} else { |
822 |
|
|
TR(TRACE_ATTRS, |
823 |
|
|
("Cookie space for %s found before (%d, %d)", |
824 |
|
|
_traceattr(turnon), i, j)); |
825 |
|
|
|
826 |
|
|
/* |
827 |
|
|
* Back up the start of range so there's room for cookies |
828 |
|
|
* before the first nonblank character. |
829 |
|
|
*/ |
830 |
|
|
for (k = 1; k <= magic_cookie_glitch; k++) |
831 |
|
|
AddAttr(thisline[j - k], turnon); |
832 |
|
|
} |
833 |
|
|
|
834 |
|
|
rattr = thisattr; |
835 |
|
|
} |
836 |
|
|
} |
837 |
|
|
|
838 |
|
|
#ifdef TRACE |
839 |
|
|
/* show altered highlights after magic-cookie check */ |
840 |
|
|
if (USE_TRACEF(TRACE_UPDATE)) { |
841 |
|
|
_tracef("After magic-cookie check..."); |
842 |
|
|
_tracedump("newscr", newscr); |
843 |
|
|
_nc_unlock_global(tracef); |
844 |
|
|
} |
845 |
|
|
#endif /* TRACE */ |
846 |
|
|
} |
847 |
|
|
#endif /* USE_XMC_SUPPORT */ |
848 |
|
|
|
849 |
|
|
nonempty = 0; |
850 |
|
|
if (curscr->_clear || newscr->_clear) { /* force refresh ? */ |
851 |
|
|
ClrUpdate(); |
852 |
|
|
curscr->_clear = FALSE; /* reset flag */ |
853 |
|
|
newscr->_clear = FALSE; /* reset flag */ |
854 |
|
|
} else { |
855 |
|
|
int changedlines = CHECK_INTERVAL; |
856 |
|
|
|
857 |
|
|
if (check_pending()) |
858 |
|
|
goto cleanup; |
859 |
|
|
|
860 |
|
|
nonempty = min(screen_lines, newscr->_maxy + 1); |
861 |
|
|
|
862 |
|
|
if (SP->_scrolling) { |
863 |
|
|
_nc_scroll_optimize(); |
864 |
|
|
} |
865 |
|
|
|
866 |
|
|
nonempty = ClrBottom(nonempty); |
867 |
|
|
|
868 |
|
|
TR(TRACE_UPDATE, ("Transforming lines, nonempty %d", nonempty)); |
869 |
|
|
for (i = 0; i < nonempty; i++) { |
870 |
|
|
/* |
871 |
|
|
* Here is our line-breakout optimization. |
872 |
|
|
*/ |
873 |
|
|
if (changedlines == CHECK_INTERVAL) { |
874 |
|
|
if (check_pending()) |
875 |
|
|
goto cleanup; |
876 |
|
|
changedlines = 0; |
877 |
|
|
} |
878 |
|
|
|
879 |
|
|
/* |
880 |
|
|
* newscr->line[i].firstchar is normally set |
881 |
|
|
* by wnoutrefresh. curscr->line[i].firstchar |
882 |
|
|
* is normally set by _nc_scroll_window in the |
883 |
|
|
* vertical-movement optimization code, |
884 |
|
|
*/ |
885 |
|
|
if (newscr->_line[i].firstchar != _NOCHANGE |
886 |
|
|
|| curscr->_line[i].firstchar != _NOCHANGE) { |
887 |
|
|
TransformLine(i); |
888 |
|
|
changedlines++; |
889 |
|
|
} |
890 |
|
|
|
891 |
|
|
/* mark line changed successfully */ |
892 |
|
|
if (i <= newscr->_maxy) { |
893 |
|
|
MARK_NOCHANGE(newscr, i); |
894 |
|
|
} |
895 |
|
|
if (i <= curscr->_maxy) { |
896 |
|
|
MARK_NOCHANGE(curscr, i); |
897 |
|
|
} |
898 |
|
|
} |
899 |
|
|
} |
900 |
|
|
|
901 |
|
|
/* put everything back in sync */ |
902 |
|
|
for (i = nonempty; i <= newscr->_maxy; i++) { |
903 |
|
|
MARK_NOCHANGE(newscr, i); |
904 |
|
|
} |
905 |
|
|
for (i = nonempty; i <= curscr->_maxy; i++) { |
906 |
|
|
MARK_NOCHANGE(curscr, i); |
907 |
|
|
} |
908 |
|
|
|
909 |
|
|
if (!newscr->_leaveok) { |
910 |
|
|
curscr->_curx = newscr->_curx; |
911 |
|
|
curscr->_cury = newscr->_cury; |
912 |
|
|
|
913 |
|
|
GoTo(curscr->_cury, curscr->_curx); |
914 |
|
|
} |
915 |
|
|
|
916 |
|
|
cleanup: |
917 |
|
|
/* |
918 |
|
|
* We would like to keep the physical screen in normal mode in case we get |
919 |
|
|
* other processes writing to the screen. This goal cannot be met for |
920 |
|
|
* magic cookies since it interferes with attributes that may propagate |
921 |
|
|
* past the current position. |
922 |
|
|
*/ |
923 |
|
|
#if USE_XMC_SUPPORT |
924 |
|
|
if (magic_cookie_glitch != 0) |
925 |
|
|
#endif |
926 |
|
|
UpdateAttrs(normal); |
927 |
|
|
|
928 |
|
|
_nc_flush(); |
929 |
|
|
WINDOW_ATTRS(curscr) = WINDOW_ATTRS(newscr); |
930 |
|
|
|
931 |
|
|
#if USE_TRACE_TIMES |
932 |
|
|
(void) times(&after); |
933 |
|
|
TR(TRACE_TIMES, |
934 |
|
|
("Update cost: %ld chars, %ld clocks system time, %ld clocks user time", |
935 |
|
|
_nc_outchars, |
936 |
|
|
(long) (after.tms_stime - before.tms_stime), |
937 |
|
|
(long) (after.tms_utime - before.tms_utime))); |
938 |
|
|
#endif /* USE_TRACE_TIMES */ |
939 |
|
|
|
940 |
|
|
_nc_signal_handler(TRUE); |
941 |
|
|
|
942 |
|
|
returnCode(OK); |
943 |
|
|
} |
944 |
|
|
|
945 |
|
|
/* |
946 |
|
|
* ClrBlank(win) |
947 |
|
|
* |
948 |
|
|
* Returns the attributed character that corresponds to the "cleared" |
949 |
|
|
* screen. If the terminal has the back-color-erase feature, this will be |
950 |
|
|
* colored according to the wbkgd() call. |
951 |
|
|
* |
952 |
|
|
* We treat 'curscr' specially because it isn't supposed to be set directly |
953 |
|
|
* in the wbkgd() call. Assume 'stdscr' for this case. |
954 |
|
|
*/ |
955 |
|
|
#define BCE_ATTRS (A_NORMAL|A_COLOR) |
956 |
|
|
#define BCE_BKGD(win) (((win) == curscr ? stdscr : (win))->_nc_bkgd) |
957 |
|
|
|
958 |
|
|
static NCURSES_INLINE NCURSES_CH_T |
959 |
|
|
ClrBlank(WINDOW *win) |
960 |
|
|
{ |
961 |
|
|
NCURSES_CH_T blank = blankchar; |
962 |
|
|
if (back_color_erase) |
963 |
|
|
AddAttr(blank, (AttrOf(BCE_BKGD(win)) & BCE_ATTRS)); |
964 |
|
|
return blank; |
965 |
|
|
} |
966 |
|
|
|
967 |
|
|
/* |
968 |
|
|
** ClrUpdate() |
969 |
|
|
** |
970 |
|
|
** Update by clearing and redrawing the entire screen. |
971 |
|
|
** |
972 |
|
|
*/ |
973 |
|
|
|
974 |
|
|
static void |
975 |
|
|
ClrUpdate(void) |
976 |
|
|
{ |
977 |
|
|
int i; |
978 |
|
|
NCURSES_CH_T blank = ClrBlank(stdscr); |
979 |
|
|
int nonempty = min(screen_lines, newscr->_maxy + 1); |
980 |
|
|
|
981 |
|
|
TR(TRACE_UPDATE, (T_CALLED("ClrUpdate"))); |
982 |
|
|
|
983 |
|
|
ClearScreen(blank); |
984 |
|
|
|
985 |
|
|
TR(TRACE_UPDATE, ("updating screen from scratch")); |
986 |
|
|
|
987 |
|
|
nonempty = ClrBottom(nonempty); |
988 |
|
|
|
989 |
|
|
for (i = 0; i < nonempty; i++) |
990 |
|
|
TransformLine(i); |
991 |
|
|
|
992 |
|
|
TR(TRACE_UPDATE, (T_RETURN(""))); |
993 |
|
|
} |
994 |
|
|
|
995 |
|
|
/* |
996 |
|
|
** ClrToEOL(blank) |
997 |
|
|
** |
998 |
|
|
** Clear to end of current line, starting at the cursor position |
999 |
|
|
*/ |
1000 |
|
|
|
1001 |
|
|
static void |
1002 |
|
|
ClrToEOL(NCURSES_CH_T blank, bool needclear) |
1003 |
|
|
{ |
1004 |
|
|
int j; |
1005 |
|
|
|
1006 |
|
|
if (curscr != 0 |
1007 |
|
|
&& SP->_cursrow >= 0) { |
1008 |
|
|
for (j = SP->_curscol; j < screen_columns; j++) { |
1009 |
|
|
if (j >= 0) { |
1010 |
|
|
NCURSES_CH_T *cp = &(curscr->_line[SP->_cursrow].text[j]); |
1011 |
|
|
|
1012 |
|
|
if (!CharEq(*cp, blank)) { |
1013 |
|
|
*cp = blank; |
1014 |
|
|
needclear = TRUE; |
1015 |
|
|
} |
1016 |
|
|
} |
1017 |
|
|
} |
1018 |
|
|
} else { |
1019 |
|
|
needclear = TRUE; |
1020 |
|
|
} |
1021 |
|
|
|
1022 |
|
|
if (needclear) { |
1023 |
|
|
UpdateAttrs(blank); |
1024 |
|
|
TPUTS_TRACE("clr_eol"); |
1025 |
|
|
if (clr_eol && SP->_el_cost <= (screen_columns - SP->_curscol)) { |
1026 |
|
|
putp(clr_eol); |
1027 |
|
|
} else { |
1028 |
|
|
int count = (screen_columns - SP->_curscol); |
1029 |
|
|
while (count-- > 0) |
1030 |
|
|
PutChar(CHREF(blank)); |
1031 |
|
|
} |
1032 |
|
|
} |
1033 |
|
|
} |
1034 |
|
|
|
1035 |
|
|
/* |
1036 |
|
|
** ClrToEOS(blank) |
1037 |
|
|
** |
1038 |
|
|
** Clear to end of screen, starting at the cursor position |
1039 |
|
|
*/ |
1040 |
|
|
|
1041 |
|
|
static void |
1042 |
|
|
ClrToEOS(NCURSES_CH_T blank) |
1043 |
|
|
{ |
1044 |
|
|
int row, col; |
1045 |
|
|
|
1046 |
|
|
row = SP->_cursrow; |
1047 |
|
|
col = SP->_curscol; |
1048 |
|
|
|
1049 |
|
|
UpdateAttrs(blank); |
1050 |
|
|
TPUTS_TRACE("clr_eos"); |
1051 |
|
|
tputs(clr_eos, screen_lines - row, _nc_outch); |
1052 |
|
|
|
1053 |
|
|
while (col < screen_columns) |
1054 |
|
|
curscr->_line[row].text[col++] = blank; |
1055 |
|
|
|
1056 |
|
|
for (row++; row < screen_lines; row++) { |
1057 |
|
|
for (col = 0; col < screen_columns; col++) |
1058 |
|
|
curscr->_line[row].text[col] = blank; |
1059 |
|
|
} |
1060 |
|
|
} |
1061 |
|
|
|
1062 |
|
|
/* |
1063 |
|
|
* ClrBottom(total) |
1064 |
|
|
* |
1065 |
|
|
* Test if clearing the end of the screen would satisfy part of the |
1066 |
|
|
* screen-update. Do this by scanning backwards through the lines in the |
1067 |
|
|
* screen, checking if each is blank, and one or more are changed. |
1068 |
|
|
*/ |
1069 |
|
|
static int |
1070 |
|
|
ClrBottom(int total) |
1071 |
|
|
{ |
1072 |
|
|
int row; |
1073 |
|
|
int col; |
1074 |
|
|
int top = total; |
1075 |
|
|
int last = min(screen_columns, newscr->_maxx + 1); |
1076 |
|
|
NCURSES_CH_T blank = newscr->_line[total - 1].text[last - 1]; |
1077 |
|
|
bool ok; |
1078 |
|
|
|
1079 |
|
|
if (clr_eos && can_clear_with(CHREF(blank))) { |
1080 |
|
|
|
1081 |
|
|
for (row = total - 1; row >= 0; row--) { |
1082 |
|
|
for (col = 0, ok = TRUE; ok && col < last; col++) { |
1083 |
|
|
ok = (CharEq(newscr->_line[row].text[col], blank)); |
1084 |
|
|
} |
1085 |
|
|
if (!ok) |
1086 |
|
|
break; |
1087 |
|
|
|
1088 |
|
|
for (col = 0; ok && col < last; col++) { |
1089 |
|
|
ok = (CharEq(curscr->_line[row].text[col], blank)); |
1090 |
|
|
} |
1091 |
|
|
if (!ok) |
1092 |
|
|
top = row; |
1093 |
|
|
} |
1094 |
|
|
|
1095 |
|
|
/* don't use clr_eos for just one line if clr_eol available */ |
1096 |
|
|
if (top < total) { |
1097 |
|
|
GoTo(top, 0); |
1098 |
|
|
ClrToEOS(blank); |
1099 |
|
|
if (SP->oldhash && SP->newhash) { |
1100 |
|
|
for (row = top; row < screen_lines; row++) |
1101 |
|
|
SP->oldhash[row] = SP->newhash[row]; |
1102 |
|
|
} |
1103 |
|
|
} |
1104 |
|
|
} |
1105 |
|
|
return top; |
1106 |
|
|
} |
1107 |
|
|
|
1108 |
|
|
#if USE_XMC_SUPPORT |
1109 |
|
|
#if USE_WIDEC_SUPPORT |
1110 |
|
|
#define check_xmc_transition(a, b) \ |
1111 |
|
|
((((a)->attr ^ (b)->attr) & ~((a)->attr) & SP->_xmc_triggers) != 0) |
1112 |
|
|
#define xmc_turn_on(a,b) check_xmc_transition(&(a), &(b)) |
1113 |
|
|
#else |
1114 |
|
|
#define xmc_turn_on(a,b) ((((a)^(b)) & ~(a) & SP->_xmc_triggers) != 0) |
1115 |
|
|
#endif |
1116 |
|
|
|
1117 |
|
|
#define xmc_new(r,c) newscr->_line[r].text[c] |
1118 |
|
|
#define xmc_turn_off(a,b) xmc_turn_on(b,a) |
1119 |
|
|
#endif /* USE_XMC_SUPPORT */ |
1120 |
|
|
|
1121 |
|
|
/* |
1122 |
|
|
** TransformLine(lineno) |
1123 |
|
|
** |
1124 |
|
|
** Transform the given line in curscr to the one in newscr, using |
1125 |
|
|
** Insert/Delete Character if _nc_idcok && has_ic(). |
1126 |
|
|
** |
1127 |
|
|
** firstChar = position of first different character in line |
1128 |
|
|
** oLastChar = position of last different character in old line |
1129 |
|
|
** nLastChar = position of last different character in new line |
1130 |
|
|
** |
1131 |
|
|
** move to firstChar |
1132 |
|
|
** overwrite chars up to min(oLastChar, nLastChar) |
1133 |
|
|
** if oLastChar < nLastChar |
1134 |
|
|
** insert newLine[oLastChar+1..nLastChar] |
1135 |
|
|
** else |
1136 |
|
|
** delete oLastChar - nLastChar spaces |
1137 |
|
|
*/ |
1138 |
|
|
|
1139 |
|
|
static void |
1140 |
|
|
TransformLine(int const lineno) |
1141 |
|
|
{ |
1142 |
|
|
int firstChar, oLastChar, nLastChar; |
1143 |
|
|
NCURSES_CH_T *newLine = newscr->_line[lineno].text; |
1144 |
|
|
NCURSES_CH_T *oldLine = curscr->_line[lineno].text; |
1145 |
|
|
int n; |
1146 |
|
|
bool attrchanged = FALSE; |
1147 |
|
|
|
1148 |
|
|
TR(TRACE_UPDATE, (T_CALLED("TransformLine(%d)"), lineno)); |
1149 |
|
|
|
1150 |
|
|
/* copy new hash value to old one */ |
1151 |
|
|
if (SP->oldhash && SP->newhash) |
1152 |
|
|
SP->oldhash[lineno] = SP->newhash[lineno]; |
1153 |
|
|
|
1154 |
|
|
/* |
1155 |
|
|
* If we have colors, there is the possibility of having two color pairs |
1156 |
|
|
* that display as the same colors. For instance, Lynx does this. Check |
1157 |
|
|
* for this case, and update the old line with the new line's colors when |
1158 |
|
|
* they are equivalent. |
1159 |
|
|
*/ |
1160 |
|
|
if (SP->_coloron) { |
1161 |
|
|
int oldPair; |
1162 |
|
|
int newPair; |
1163 |
|
|
|
1164 |
|
|
for (n = 0; n < screen_columns; n++) { |
1165 |
|
|
if (!CharEq(newLine[n], oldLine[n])) { |
1166 |
|
|
oldPair = GetPair(oldLine[n]); |
1167 |
|
|
newPair = GetPair(newLine[n]); |
1168 |
|
|
if (oldPair != newPair |
1169 |
|
|
&& unColor(oldLine[n]) == unColor(newLine[n])) { |
1170 |
|
|
if (oldPair < COLOR_PAIRS |
1171 |
|
|
&& newPair < COLOR_PAIRS |
1172 |
|
|
&& SP->_color_pairs[oldPair] == SP->_color_pairs[newPair]) { |
1173 |
|
|
SetPair(oldLine[n], GetPair(newLine[n])); |
1174 |
|
|
} |
1175 |
|
|
} |
1176 |
|
|
} |
1177 |
|
|
} |
1178 |
|
|
} |
1179 |
|
|
|
1180 |
|
|
if (ceol_standout_glitch && clr_eol) { |
1181 |
|
|
firstChar = 0; |
1182 |
|
|
while (firstChar < screen_columns) { |
1183 |
|
|
if (!SameAttrOf(newLine[firstChar], oldLine[firstChar])) { |
1184 |
|
|
attrchanged = TRUE; |
1185 |
|
|
break; |
1186 |
|
|
} |
1187 |
|
|
firstChar++; |
1188 |
|
|
} |
1189 |
|
|
} |
1190 |
|
|
|
1191 |
|
|
firstChar = 0; |
1192 |
|
|
|
1193 |
|
|
if (attrchanged) { /* we may have to disregard the whole line */ |
1194 |
|
|
GoTo(lineno, firstChar); |
1195 |
|
|
ClrToEOL(ClrBlank(curscr), FALSE); |
1196 |
|
|
PutRange(oldLine, newLine, lineno, 0, (screen_columns - 1)); |
1197 |
|
|
#if USE_XMC_SUPPORT |
1198 |
|
|
|
1199 |
|
|
/* |
1200 |
|
|
* This is a very simple loop to paint characters which may have the |
1201 |
|
|
* magic cookie glitch embedded. It doesn't know much about video |
1202 |
|
|
* attributes which are continued from one line to the next. It |
1203 |
|
|
* assumes that we have filtered out requests for attribute changes |
1204 |
|
|
* that do not get mapped to blank positions. |
1205 |
|
|
* |
1206 |
|
|
* FIXME: we are not keeping track of where we put the cookies, so this |
1207 |
|
|
* will work properly only once, since we may overwrite a cookie in a |
1208 |
|
|
* following operation. |
1209 |
|
|
*/ |
1210 |
|
|
} else if (magic_cookie_glitch > 0) { |
1211 |
|
|
GoTo(lineno, firstChar); |
1212 |
|
|
for (n = 0; n < screen_columns; n++) { |
1213 |
|
|
int m = n + magic_cookie_glitch; |
1214 |
|
|
|
1215 |
|
|
/* check for turn-on: |
1216 |
|
|
* If we are writing an attributed blank, where the |
1217 |
|
|
* previous cell is not attributed. |
1218 |
|
|
*/ |
1219 |
|
|
if (ISBLANK(newLine[n]) |
1220 |
|
|
&& ((n > 0 |
1221 |
|
|
&& xmc_turn_on(newLine[n - 1], newLine[n])) |
1222 |
|
|
|| (n == 0 |
1223 |
|
|
&& lineno > 0 |
1224 |
|
|
&& xmc_turn_on(xmc_new(lineno - 1, screen_columns - 1), |
1225 |
|
|
newLine[n])))) { |
1226 |
|
|
n = m; |
1227 |
|
|
} |
1228 |
|
|
|
1229 |
|
|
PutChar(CHREF(newLine[n])); |
1230 |
|
|
|
1231 |
|
|
/* check for turn-off: |
1232 |
|
|
* If we are writing an attributed non-blank, where the |
1233 |
|
|
* next cell is blank, and not attributed. |
1234 |
|
|
*/ |
1235 |
|
|
if (!ISBLANK(newLine[n]) |
1236 |
|
|
&& ((n + 1 < screen_columns |
1237 |
|
|
&& xmc_turn_off(newLine[n], newLine[n + 1])) |
1238 |
|
|
|| (n + 1 >= screen_columns |
1239 |
|
|
&& lineno + 1 < screen_lines |
1240 |
|
|
&& xmc_turn_off(newLine[n], xmc_new(lineno + 1, 0))))) { |
1241 |
|
|
n = m; |
1242 |
|
|
} |
1243 |
|
|
|
1244 |
|
|
} |
1245 |
|
|
#endif |
1246 |
|
|
} else { |
1247 |
|
|
NCURSES_CH_T blank; |
1248 |
|
|
|
1249 |
|
|
/* it may be cheap to clear leading whitespace with clr_bol */ |
1250 |
|
|
blank = newLine[0]; |
1251 |
|
|
if (clr_bol && can_clear_with(CHREF(blank))) { |
1252 |
|
|
int oFirstChar, nFirstChar; |
1253 |
|
|
|
1254 |
|
|
for (oFirstChar = 0; oFirstChar < screen_columns; oFirstChar++) |
1255 |
|
|
if (!CharEq(oldLine[oFirstChar], blank)) |
1256 |
|
|
break; |
1257 |
|
|
for (nFirstChar = 0; nFirstChar < screen_columns; nFirstChar++) |
1258 |
|
|
if (!CharEq(newLine[nFirstChar], blank)) |
1259 |
|
|
break; |
1260 |
|
|
|
1261 |
|
|
if (nFirstChar == oFirstChar) { |
1262 |
|
|
firstChar = nFirstChar; |
1263 |
|
|
/* find the first differing character */ |
1264 |
|
|
while (firstChar < screen_columns |
1265 |
|
|
&& CharEq(newLine[firstChar], oldLine[firstChar])) |
1266 |
|
|
firstChar++; |
1267 |
|
|
} else if (oFirstChar > nFirstChar) { |
1268 |
|
|
firstChar = nFirstChar; |
1269 |
|
|
} else { /* oFirstChar < nFirstChar */ |
1270 |
|
|
firstChar = oFirstChar; |
1271 |
|
|
if (SP->_el1_cost < nFirstChar - oFirstChar) { |
1272 |
|
|
if (nFirstChar >= screen_columns |
1273 |
|
|
&& SP->_el_cost <= SP->_el1_cost) { |
1274 |
|
|
GoTo(lineno, 0); |
1275 |
|
|
UpdateAttrs(blank); |
1276 |
|
|
TPUTS_TRACE("clr_eol"); |
1277 |
|
|
putp(clr_eol); |
1278 |
|
|
} else { |
1279 |
|
|
GoTo(lineno, nFirstChar - 1); |
1280 |
|
|
UpdateAttrs(blank); |
1281 |
|
|
TPUTS_TRACE("clr_bol"); |
1282 |
|
|
putp(clr_bol); |
1283 |
|
|
} |
1284 |
|
|
|
1285 |
|
|
while (firstChar < nFirstChar) |
1286 |
|
|
oldLine[firstChar++] = blank; |
1287 |
|
|
} |
1288 |
|
|
} |
1289 |
|
|
} else { |
1290 |
|
|
/* find the first differing character */ |
1291 |
|
|
while (firstChar < screen_columns |
1292 |
|
|
&& CharEq(newLine[firstChar], oldLine[firstChar])) |
1293 |
|
|
firstChar++; |
1294 |
|
|
} |
1295 |
|
|
/* if there wasn't one, we're done */ |
1296 |
|
|
if (firstChar >= screen_columns) { |
1297 |
|
|
TR(TRACE_UPDATE, (T_RETURN(""))); |
1298 |
|
|
return; |
1299 |
|
|
} |
1300 |
|
|
|
1301 |
|
|
blank = newLine[screen_columns - 1]; |
1302 |
|
|
|
1303 |
|
|
if (!can_clear_with(CHREF(blank))) { |
1304 |
|
|
/* find the last differing character */ |
1305 |
|
|
nLastChar = screen_columns - 1; |
1306 |
|
|
|
1307 |
|
|
while (nLastChar > firstChar |
1308 |
|
|
&& CharEq(newLine[nLastChar], oldLine[nLastChar])) |
1309 |
|
|
nLastChar--; |
1310 |
|
|
|
1311 |
|
|
if (nLastChar >= firstChar) { |
1312 |
|
|
GoTo(lineno, firstChar); |
1313 |
|
|
PutRange(oldLine, newLine, lineno, firstChar, nLastChar); |
1314 |
|
|
memcpy(oldLine + firstChar, |
1315 |
|
|
newLine + firstChar, |
1316 |
|
|
(nLastChar - firstChar + 1) * sizeof(NCURSES_CH_T)); |
1317 |
|
|
} |
1318 |
|
|
TR(TRACE_UPDATE, (T_RETURN(""))); |
1319 |
|
|
return; |
1320 |
|
|
} |
1321 |
|
|
|
1322 |
|
|
/* find last non-blank character on old line */ |
1323 |
|
|
oLastChar = screen_columns - 1; |
1324 |
|
|
while (oLastChar > firstChar && CharEq(oldLine[oLastChar], blank)) |
1325 |
|
|
oLastChar--; |
1326 |
|
|
|
1327 |
|
|
/* find last non-blank character on new line */ |
1328 |
|
|
nLastChar = screen_columns - 1; |
1329 |
|
|
while (nLastChar > firstChar && CharEq(newLine[nLastChar], blank)) |
1330 |
|
|
nLastChar--; |
1331 |
|
|
|
1332 |
|
|
if ((nLastChar == firstChar) |
1333 |
|
|
&& (SP->_el_cost < (oLastChar - nLastChar))) { |
1334 |
|
|
GoTo(lineno, firstChar); |
1335 |
|
|
if (!CharEq(newLine[firstChar], blank)) |
1336 |
|
|
PutChar(CHREF(newLine[firstChar])); |
1337 |
|
|
ClrToEOL(blank, FALSE); |
1338 |
|
|
} else if ((nLastChar != oLastChar) |
1339 |
|
|
&& (!CharEq(newLine[nLastChar], oldLine[oLastChar]) |
1340 |
|
|
|| !(_nc_idcok && has_ic()))) { |
1341 |
|
|
GoTo(lineno, firstChar); |
1342 |
|
|
if ((oLastChar - nLastChar) > SP->_el_cost) { |
1343 |
|
|
if (PutRange(oldLine, newLine, lineno, firstChar, nLastChar)) |
1344 |
|
|
GoTo(lineno, nLastChar + 1); |
1345 |
|
|
ClrToEOL(blank, FALSE); |
1346 |
|
|
} else { |
1347 |
|
|
n = max(nLastChar, oLastChar); |
1348 |
|
|
PutRange(oldLine, newLine, lineno, firstChar, n); |
1349 |
|
|
} |
1350 |
|
|
} else { |
1351 |
|
|
int nLastNonblank = nLastChar; |
1352 |
|
|
int oLastNonblank = oLastChar; |
1353 |
|
|
|
1354 |
|
|
/* find the last characters that really differ */ |
1355 |
|
|
/* can be -1 if no characters differ */ |
1356 |
|
|
while (CharEq(newLine[nLastChar], oldLine[oLastChar])) { |
1357 |
|
|
/* don't split a wide char */ |
1358 |
|
|
if (isWidecExt(newLine[nLastChar]) && |
1359 |
|
|
!CharEq(newLine[nLastChar - 1], oldLine[oLastChar - 1])) |
1360 |
|
|
break; |
1361 |
|
|
nLastChar--; |
1362 |
|
|
oLastChar--; |
1363 |
|
|
if (nLastChar == -1 || oLastChar == -1) |
1364 |
|
|
break; |
1365 |
|
|
} |
1366 |
|
|
|
1367 |
|
|
n = min(oLastChar, nLastChar); |
1368 |
|
|
if (n >= firstChar) { |
1369 |
|
|
GoTo(lineno, firstChar); |
1370 |
|
|
PutRange(oldLine, newLine, lineno, firstChar, n); |
1371 |
|
|
} |
1372 |
|
|
|
1373 |
|
|
if (oLastChar < nLastChar) { |
1374 |
|
|
int m = max(nLastNonblank, oLastNonblank); |
1375 |
|
|
#if USE_WIDEC_SUPPORT |
1376 |
|
|
while (isWidecExt(newLine[n + 1]) && n) { |
1377 |
|
|
--n; |
1378 |
|
|
--oLastChar; |
1379 |
|
|
} |
1380 |
|
|
#endif |
1381 |
|
|
GoTo(lineno, n + 1); |
1382 |
|
|
if ((nLastChar < nLastNonblank) |
1383 |
|
|
|| InsCharCost(nLastChar - oLastChar) > (m - n)) { |
1384 |
|
|
PutRange(oldLine, newLine, lineno, n + 1, m); |
1385 |
|
|
} else { |
1386 |
|
|
InsStr(&newLine[n + 1], nLastChar - oLastChar); |
1387 |
|
|
} |
1388 |
|
|
} else if (oLastChar > nLastChar) { |
1389 |
|
|
GoTo(lineno, n + 1); |
1390 |
|
|
if (DelCharCost(oLastChar - nLastChar) |
1391 |
|
|
> SP->_el_cost + nLastNonblank - (n + 1)) { |
1392 |
|
|
if (PutRange(oldLine, newLine, lineno, |
1393 |
|
|
n + 1, nLastNonblank)) |
1394 |
|
|
GoTo(lineno, nLastNonblank + 1); |
1395 |
|
|
ClrToEOL(blank, FALSE); |
1396 |
|
|
} else { |
1397 |
|
|
/* |
1398 |
|
|
* The delete-char sequence will |
1399 |
|
|
* effectively shift in blanks from the |
1400 |
|
|
* right margin of the screen. Ensure |
1401 |
|
|
* that they are the right color by |
1402 |
|
|
* setting the video attributes from |
1403 |
|
|
* the last character on the row. |
1404 |
|
|
*/ |
1405 |
|
|
UpdateAttrs(blank); |
1406 |
|
|
DelChar(oLastChar - nLastChar); |
1407 |
|
|
} |
1408 |
|
|
} |
1409 |
|
|
} |
1410 |
|
|
} |
1411 |
|
|
|
1412 |
|
|
/* update the code's internal representation */ |
1413 |
|
|
if (screen_columns > firstChar) |
1414 |
|
|
memcpy(oldLine + firstChar, |
1415 |
|
|
newLine + firstChar, |
1416 |
|
|
(screen_columns - firstChar) * sizeof(NCURSES_CH_T)); |
1417 |
|
|
TR(TRACE_UPDATE, (T_RETURN(""))); |
1418 |
|
|
return; |
1419 |
|
|
} |
1420 |
|
|
|
1421 |
|
|
/* |
1422 |
|
|
** ClearScreen(blank) |
1423 |
|
|
** |
1424 |
|
|
** Clear the physical screen and put cursor at home |
1425 |
|
|
** |
1426 |
|
|
*/ |
1427 |
|
|
|
1428 |
|
|
static void |
1429 |
|
|
ClearScreen(NCURSES_CH_T blank) |
1430 |
|
|
{ |
1431 |
|
|
int i, j; |
1432 |
|
|
bool fast_clear = (clear_screen || clr_eos || clr_eol); |
1433 |
|
|
|
1434 |
|
|
TR(TRACE_UPDATE, ("ClearScreen() called")); |
1435 |
|
|
|
1436 |
|
|
#if NCURSES_EXT_FUNCS |
1437 |
|
|
if (SP->_coloron |
1438 |
|
|
&& !SP->_default_color) { |
1439 |
|
|
_nc_do_color(GET_SCREEN_PAIR(SP), 0, FALSE, _nc_outch); |
1440 |
|
|
if (!back_color_erase) { |
1441 |
|
|
fast_clear = FALSE; |
1442 |
|
|
} |
1443 |
|
|
} |
1444 |
|
|
#endif |
1445 |
|
|
|
1446 |
|
|
if (fast_clear) { |
1447 |
|
|
if (clear_screen) { |
1448 |
|
|
UpdateAttrs(blank); |
1449 |
|
|
TPUTS_TRACE("clear_screen"); |
1450 |
|
|
putp(clear_screen); |
1451 |
|
|
SP->_cursrow = SP->_curscol = 0; |
1452 |
|
|
position_check(SP->_cursrow, SP->_curscol, "ClearScreen"); |
1453 |
|
|
} else if (clr_eos) { |
1454 |
|
|
SP->_cursrow = SP->_curscol = -1; |
1455 |
|
|
GoTo(0, 0); |
1456 |
|
|
|
1457 |
|
|
UpdateAttrs(blank); |
1458 |
|
|
TPUTS_TRACE("clr_eos"); |
1459 |
|
|
tputs(clr_eos, screen_lines, _nc_outch); |
1460 |
|
|
} else if (clr_eol) { |
1461 |
|
|
SP->_cursrow = SP->_curscol = -1; |
1462 |
|
|
|
1463 |
|
|
UpdateAttrs(blank); |
1464 |
|
|
for (i = 0; i < screen_lines; i++) { |
1465 |
|
|
GoTo(i, 0); |
1466 |
|
|
TPUTS_TRACE("clr_eol"); |
1467 |
|
|
putp(clr_eol); |
1468 |
|
|
} |
1469 |
|
|
GoTo(0, 0); |
1470 |
|
|
} |
1471 |
|
|
} else { |
1472 |
|
|
UpdateAttrs(blank); |
1473 |
|
|
for (i = 0; i < screen_lines; i++) { |
1474 |
|
|
GoTo(i, 0); |
1475 |
|
|
for (j = 0; j < screen_columns; j++) |
1476 |
|
|
PutChar(CHREF(blank)); |
1477 |
|
|
} |
1478 |
|
|
GoTo(0, 0); |
1479 |
|
|
} |
1480 |
|
|
|
1481 |
|
|
for (i = 0; i < screen_lines; i++) { |
1482 |
|
|
for (j = 0; j < screen_columns; j++) |
1483 |
|
|
curscr->_line[i].text[j] = blank; |
1484 |
|
|
} |
1485 |
|
|
|
1486 |
|
|
TR(TRACE_UPDATE, ("screen cleared")); |
1487 |
|
|
} |
1488 |
|
|
|
1489 |
|
|
/* |
1490 |
|
|
** InsStr(line, count) |
1491 |
|
|
** |
1492 |
|
|
** Insert the count characters pointed to by line. |
1493 |
|
|
** |
1494 |
|
|
*/ |
1495 |
|
|
|
1496 |
|
|
static void |
1497 |
|
|
InsStr(NCURSES_CH_T * line, int count) |
1498 |
|
|
{ |
1499 |
|
|
TR(TRACE_UPDATE, ("InsStr(%p,%d) called", line, count)); |
1500 |
|
|
|
1501 |
|
|
/* Prefer parm_ich as it has the smallest cost - no need to shift |
1502 |
|
|
* the whole line on each character. */ |
1503 |
|
|
/* The order must match that of InsCharCost. */ |
1504 |
|
|
if (parm_ich) { |
1505 |
|
|
TPUTS_TRACE("parm_ich"); |
1506 |
|
|
tputs(TPARM_1(parm_ich, count), count, _nc_outch); |
1507 |
|
|
while (count) { |
1508 |
|
|
PutAttrChar(CHREF(*line)); |
1509 |
|
|
line++; |
1510 |
|
|
count--; |
1511 |
|
|
} |
1512 |
|
|
} else if (enter_insert_mode && exit_insert_mode) { |
1513 |
|
|
TPUTS_TRACE("enter_insert_mode"); |
1514 |
|
|
putp(enter_insert_mode); |
1515 |
|
|
while (count) { |
1516 |
|
|
PutAttrChar(CHREF(*line)); |
1517 |
|
|
if (insert_padding) { |
1518 |
|
|
TPUTS_TRACE("insert_padding"); |
1519 |
|
|
putp(insert_padding); |
1520 |
|
|
} |
1521 |
|
|
line++; |
1522 |
|
|
count--; |
1523 |
|
|
} |
1524 |
|
|
TPUTS_TRACE("exit_insert_mode"); |
1525 |
|
|
putp(exit_insert_mode); |
1526 |
|
|
} else { |
1527 |
|
|
while (count) { |
1528 |
|
|
TPUTS_TRACE("insert_character"); |
1529 |
|
|
putp(insert_character); |
1530 |
|
|
PutAttrChar(CHREF(*line)); |
1531 |
|
|
if (insert_padding) { |
1532 |
|
|
TPUTS_TRACE("insert_padding"); |
1533 |
|
|
putp(insert_padding); |
1534 |
|
|
} |
1535 |
|
|
line++; |
1536 |
|
|
count--; |
1537 |
|
|
} |
1538 |
|
|
} |
1539 |
|
|
position_check(SP->_cursrow, SP->_curscol, "InsStr"); |
1540 |
|
|
} |
1541 |
|
|
|
1542 |
|
|
/* |
1543 |
|
|
** DelChar(count) |
1544 |
|
|
** |
1545 |
|
|
** Delete count characters at current position |
1546 |
|
|
** |
1547 |
|
|
*/ |
1548 |
|
|
|
1549 |
|
|
static void |
1550 |
|
|
DelChar(int count) |
1551 |
|
|
{ |
1552 |
|
|
int n; |
1553 |
|
|
|
1554 |
|
|
TR(TRACE_UPDATE, ("DelChar(%d) called, position = (%ld,%ld)", |
1555 |
|
|
count, |
1556 |
|
|
(long) newscr->_cury, |
1557 |
|
|
(long) newscr->_curx)); |
1558 |
|
|
|
1559 |
|
|
if (parm_dch) { |
1560 |
|
|
TPUTS_TRACE("parm_dch"); |
1561 |
|
|
tputs(TPARM_1(parm_dch, count), count, _nc_outch); |
1562 |
|
|
} else { |
1563 |
|
|
for (n = 0; n < count; n++) { |
1564 |
|
|
TPUTS_TRACE("delete_character"); |
1565 |
|
|
putp(delete_character); |
1566 |
|
|
} |
1567 |
|
|
} |
1568 |
|
|
} |
1569 |
|
|
|
1570 |
|
|
/* |
1571 |
|
|
* Physical-scrolling support |
1572 |
|
|
* |
1573 |
|
|
* This code was adapted from Keith Bostic's hardware scrolling |
1574 |
|
|
* support for 4.4BSD curses. I (esr) translated it to use terminfo |
1575 |
|
|
* capabilities, narrowed the call interface slightly, and cleaned |
1576 |
|
|
* up some convoluted tests. I also added support for the memory_above |
1577 |
|
|
* memory_below, and non_dest_scroll_region capabilities. |
1578 |
|
|
* |
1579 |
|
|
* For this code to work, we must have either |
1580 |
|
|
* change_scroll_region and scroll forward/reverse commands, or |
1581 |
|
|
* insert and delete line capabilities. |
1582 |
|
|
* When the scrolling region has been set, the cursor has to |
1583 |
|
|
* be at the last line of the region to make the scroll up |
1584 |
|
|
* happen, or on the first line of region to scroll down. |
1585 |
|
|
* |
1586 |
|
|
* This code makes one aesthetic decision in the opposite way from |
1587 |
|
|
* BSD curses. BSD curses preferred pairs of il/dl operations |
1588 |
|
|
* over scrolls, allegedly because il/dl looked faster. We, on |
1589 |
|
|
* the other hand, prefer scrolls because (a) they're just as fast |
1590 |
|
|
* on many terminals and (b) using them avoids bouncing an |
1591 |
|
|
* unchanged bottom section of the screen up and down, which is |
1592 |
|
|
* visually nasty. |
1593 |
|
|
* |
1594 |
|
|
* (lav): added more cases, used dl/il when bot==maxy and in csr case. |
1595 |
|
|
* |
1596 |
|
|
* I used assumption that capabilities il/il1/dl/dl1 work inside |
1597 |
|
|
* changed scroll region not shifting screen contents outside of it. |
1598 |
|
|
* If there are any terminals behaving different way, it would be |
1599 |
|
|
* necessary to add some conditions to scroll_csr_forward/backward. |
1600 |
|
|
*/ |
1601 |
|
|
|
1602 |
|
|
/* Try to scroll up assuming given csr (miny, maxy). Returns ERR on failure */ |
1603 |
|
|
static int |
1604 |
|
|
scroll_csr_forward(int n, int top, int bot, int miny, int maxy, NCURSES_CH_T blank) |
1605 |
|
|
{ |
1606 |
|
|
int i; |
1607 |
|
|
|
1608 |
|
|
if (n == 1 && scroll_forward && top == miny && bot == maxy) { |
1609 |
|
|
GoTo(bot, 0); |
1610 |
|
|
UpdateAttrs(blank); |
1611 |
|
|
TPUTS_TRACE("scroll_forward"); |
1612 |
|
|
putp(scroll_forward); |
1613 |
|
|
} else if (n == 1 && delete_line && bot == maxy) { |
1614 |
|
|
GoTo(top, 0); |
1615 |
|
|
UpdateAttrs(blank); |
1616 |
|
|
TPUTS_TRACE("delete_line"); |
1617 |
|
|
putp(delete_line); |
1618 |
|
|
} else if (parm_index && top == miny && bot == maxy) { |
1619 |
|
|
GoTo(bot, 0); |
1620 |
|
|
UpdateAttrs(blank); |
1621 |
|
|
TPUTS_TRACE("parm_index"); |
1622 |
|
|
tputs(TPARM_2(parm_index, n, 0), n, _nc_outch); |
1623 |
|
|
} else if (parm_delete_line && bot == maxy) { |
1624 |
|
|
GoTo(top, 0); |
1625 |
|
|
UpdateAttrs(blank); |
1626 |
|
|
TPUTS_TRACE("parm_delete_line"); |
1627 |
|
|
tputs(TPARM_2(parm_delete_line, n, 0), n, _nc_outch); |
1628 |
|
|
} else if (scroll_forward && top == miny && bot == maxy) { |
1629 |
|
|
GoTo(bot, 0); |
1630 |
|
|
UpdateAttrs(blank); |
1631 |
|
|
for (i = 0; i < n; i++) { |
1632 |
|
|
TPUTS_TRACE("scroll_forward"); |
1633 |
|
|
putp(scroll_forward); |
1634 |
|
|
} |
1635 |
|
|
} else if (delete_line && bot == maxy) { |
1636 |
|
|
GoTo(top, 0); |
1637 |
|
|
UpdateAttrs(blank); |
1638 |
|
|
for (i = 0; i < n; i++) { |
1639 |
|
|
TPUTS_TRACE("delete_line"); |
1640 |
|
|
putp(delete_line); |
1641 |
|
|
} |
1642 |
|
|
} else |
1643 |
|
|
return ERR; |
1644 |
|
|
|
1645 |
|
|
#if NCURSES_EXT_FUNCS |
1646 |
|
|
if (FILL_BCE()) { |
1647 |
|
|
int j; |
1648 |
|
|
for (i = 0; i < n; i++) { |
1649 |
|
|
GoTo(bot - i, 0); |
1650 |
|
|
for (j = 0; j < screen_columns; j++) |
1651 |
|
|
PutChar(CHREF(blank)); |
1652 |
|
|
} |
1653 |
|
|
} |
1654 |
|
|
#endif |
1655 |
|
|
return OK; |
1656 |
|
|
} |
1657 |
|
|
|
1658 |
|
|
/* Try to scroll down assuming given csr (miny, maxy). Returns ERR on failure */ |
1659 |
|
|
/* n > 0 */ |
1660 |
|
|
static int |
1661 |
|
|
scroll_csr_backward(int n, int top, int bot, int miny, int maxy, |
1662 |
|
|
NCURSES_CH_T blank) |
1663 |
|
|
{ |
1664 |
|
|
int i; |
1665 |
|
|
|
1666 |
|
|
if (n == 1 && scroll_reverse && top == miny && bot == maxy) { |
1667 |
|
|
GoTo(top, 0); |
1668 |
|
|
UpdateAttrs(blank); |
1669 |
|
|
TPUTS_TRACE("scroll_reverse"); |
1670 |
|
|
putp(scroll_reverse); |
1671 |
|
|
} else if (n == 1 && insert_line && bot == maxy) { |
1672 |
|
|
GoTo(top, 0); |
1673 |
|
|
UpdateAttrs(blank); |
1674 |
|
|
TPUTS_TRACE("insert_line"); |
1675 |
|
|
putp(insert_line); |
1676 |
|
|
} else if (parm_rindex && top == miny && bot == maxy) { |
1677 |
|
|
GoTo(top, 0); |
1678 |
|
|
UpdateAttrs(blank); |
1679 |
|
|
TPUTS_TRACE("parm_rindex"); |
1680 |
|
|
tputs(TPARM_2(parm_rindex, n, 0), n, _nc_outch); |
1681 |
|
|
} else if (parm_insert_line && bot == maxy) { |
1682 |
|
|
GoTo(top, 0); |
1683 |
|
|
UpdateAttrs(blank); |
1684 |
|
|
TPUTS_TRACE("parm_insert_line"); |
1685 |
|
|
tputs(TPARM_2(parm_insert_line, n, 0), n, _nc_outch); |
1686 |
|
|
} else if (scroll_reverse && top == miny && bot == maxy) { |
1687 |
|
|
GoTo(top, 0); |
1688 |
|
|
UpdateAttrs(blank); |
1689 |
|
|
for (i = 0; i < n; i++) { |
1690 |
|
|
TPUTS_TRACE("scroll_reverse"); |
1691 |
|
|
putp(scroll_reverse); |
1692 |
|
|
} |
1693 |
|
|
} else if (insert_line && bot == maxy) { |
1694 |
|
|
GoTo(top, 0); |
1695 |
|
|
UpdateAttrs(blank); |
1696 |
|
|
for (i = 0; i < n; i++) { |
1697 |
|
|
TPUTS_TRACE("insert_line"); |
1698 |
|
|
putp(insert_line); |
1699 |
|
|
} |
1700 |
|
|
} else |
1701 |
|
|
return ERR; |
1702 |
|
|
|
1703 |
|
|
#if NCURSES_EXT_FUNCS |
1704 |
|
|
if (FILL_BCE()) { |
1705 |
|
|
int j; |
1706 |
|
|
for (i = 0; i < n; i++) { |
1707 |
|
|
GoTo(top + i, 0); |
1708 |
|
|
for (j = 0; j < screen_columns; j++) |
1709 |
|
|
PutChar(CHREF(blank)); |
1710 |
|
|
} |
1711 |
|
|
} |
1712 |
|
|
#endif |
1713 |
|
|
return OK; |
1714 |
|
|
} |
1715 |
|
|
|
1716 |
|
|
/* scroll by using delete_line at del and insert_line at ins */ |
1717 |
|
|
/* n > 0 */ |
1718 |
|
|
static int |
1719 |
|
|
scroll_idl(int n, int del, int ins, NCURSES_CH_T blank) |
1720 |
|
|
{ |
1721 |
|
|
int i; |
1722 |
|
|
|
1723 |
|
|
if (!((parm_delete_line || delete_line) && (parm_insert_line || insert_line))) |
1724 |
|
|
return ERR; |
1725 |
|
|
|
1726 |
|
|
GoTo(del, 0); |
1727 |
|
|
UpdateAttrs(blank); |
1728 |
|
|
if (n == 1 && delete_line) { |
1729 |
|
|
TPUTS_TRACE("delete_line"); |
1730 |
|
|
putp(delete_line); |
1731 |
|
|
} else if (parm_delete_line) { |
1732 |
|
|
TPUTS_TRACE("parm_delete_line"); |
1733 |
|
|
tputs(TPARM_2(parm_delete_line, n, 0), n, _nc_outch); |
1734 |
|
|
} else { /* if (delete_line) */ |
1735 |
|
|
for (i = 0; i < n; i++) { |
1736 |
|
|
TPUTS_TRACE("delete_line"); |
1737 |
|
|
putp(delete_line); |
1738 |
|
|
} |
1739 |
|
|
} |
1740 |
|
|
|
1741 |
|
|
GoTo(ins, 0); |
1742 |
|
|
UpdateAttrs(blank); |
1743 |
|
|
if (n == 1 && insert_line) { |
1744 |
|
|
TPUTS_TRACE("insert_line"); |
1745 |
|
|
putp(insert_line); |
1746 |
|
|
} else if (parm_insert_line) { |
1747 |
|
|
TPUTS_TRACE("parm_insert_line"); |
1748 |
|
|
tputs(TPARM_2(parm_insert_line, n, 0), n, _nc_outch); |
1749 |
|
|
} else { /* if (insert_line) */ |
1750 |
|
|
for (i = 0; i < n; i++) { |
1751 |
|
|
TPUTS_TRACE("insert_line"); |
1752 |
|
|
putp(insert_line); |
1753 |
|
|
} |
1754 |
|
|
} |
1755 |
|
|
|
1756 |
|
|
return OK; |
1757 |
|
|
} |
1758 |
|
|
|
1759 |
|
|
/* |
1760 |
|
|
* Note: some terminals require the cursor to be within the scrolling margins |
1761 |
|
|
* before setting them. Generally, the cursor must be at the appropriate end |
1762 |
|
|
* of the scrolling margins when issuing an indexing operation (it is not |
1763 |
|
|
* apparent whether it must also be at the left margin; we do this just to be |
1764 |
|
|
* safe). To make the related cursor movement a little faster, we use the |
1765 |
|
|
* save/restore cursor capabilities if the terminal has them. |
1766 |
|
|
*/ |
1767 |
|
|
NCURSES_EXPORT(int) |
1768 |
|
|
_nc_scrolln(int n, int top, int bot, int maxy) |
1769 |
|
|
/* scroll region from top to bot by n lines */ |
1770 |
|
|
{ |
1771 |
|
|
NCURSES_CH_T blank = ClrBlank(stdscr); |
1772 |
|
|
int i; |
1773 |
|
|
bool cursor_saved = FALSE; |
1774 |
|
|
int res; |
1775 |
|
|
|
1776 |
|
|
TR(TRACE_MOVE, ("mvcur_scrolln(%d, %d, %d, %d)", n, top, bot, maxy)); |
1777 |
|
|
|
1778 |
|
|
#if USE_XMC_SUPPORT |
1779 |
|
|
/* |
1780 |
|
|
* If we scroll, we might remove a cookie. |
1781 |
|
|
*/ |
1782 |
|
|
if (magic_cookie_glitch > 0) { |
1783 |
|
|
return (ERR); |
1784 |
|
|
} |
1785 |
|
|
#endif |
1786 |
|
|
|
1787 |
|
|
if (n > 0) { /* scroll up (forward) */ |
1788 |
|
|
/* |
1789 |
|
|
* Explicitly clear if stuff pushed off top of region might |
1790 |
|
|
* be saved by the terminal. |
1791 |
|
|
*/ |
1792 |
|
|
res = scroll_csr_forward(n, top, bot, 0, maxy, blank); |
1793 |
|
|
|
1794 |
|
|
if (res == ERR && change_scroll_region) { |
1795 |
|
|
if ((((n == 1 && scroll_forward) || parm_index) |
1796 |
|
|
&& (SP->_cursrow == bot || SP->_cursrow == bot - 1)) |
1797 |
|
|
&& save_cursor && restore_cursor) { |
1798 |
|
|
cursor_saved = TRUE; |
1799 |
|
|
TPUTS_TRACE("save_cursor"); |
1800 |
|
|
putp(save_cursor); |
1801 |
|
|
} |
1802 |
|
|
TPUTS_TRACE("change_scroll_region"); |
1803 |
|
|
putp(TPARM_2(change_scroll_region, top, bot)); |
1804 |
|
|
if (cursor_saved) { |
1805 |
|
|
TPUTS_TRACE("restore_cursor"); |
1806 |
|
|
putp(restore_cursor); |
1807 |
|
|
} else { |
1808 |
|
|
SP->_cursrow = SP->_curscol = -1; |
1809 |
|
|
} |
1810 |
|
|
|
1811 |
|
|
res = scroll_csr_forward(n, top, bot, top, bot, blank); |
1812 |
|
|
|
1813 |
|
|
TPUTS_TRACE("change_scroll_region"); |
1814 |
|
|
putp(TPARM_2(change_scroll_region, 0, maxy)); |
1815 |
|
|
SP->_cursrow = SP->_curscol = -1; |
1816 |
|
|
} |
1817 |
|
|
|
1818 |
|
|
if (res == ERR && _nc_idlok) |
1819 |
|
|
res = scroll_idl(n, top, bot - n + 1, blank); |
1820 |
|
|
|
1821 |
|
|
/* |
1822 |
|
|
* Clear the newly shifted-in text. |
1823 |
|
|
*/ |
1824 |
|
|
if (res != ERR |
1825 |
|
|
&& (non_dest_scroll_region || (memory_below && bot == maxy))) { |
1826 |
|
|
static const NCURSES_CH_T blank2 = NewChar(BLANK_TEXT); |
1827 |
|
|
if (bot == maxy && clr_eos) { |
1828 |
|
|
GoTo(bot - n + 1, 0); |
1829 |
|
|
ClrToEOS(blank2); |
1830 |
|
|
} else { |
1831 |
|
|
for (i = 0; i < n; i++) { |
1832 |
|
|
GoTo(bot - i, 0); |
1833 |
|
|
ClrToEOL(blank2, FALSE); |
1834 |
|
|
} |
1835 |
|
|
} |
1836 |
|
|
} |
1837 |
|
|
|
1838 |
|
|
} else { /* (n < 0) - scroll down (backward) */ |
1839 |
|
|
res = scroll_csr_backward(-n, top, bot, 0, maxy, blank); |
1840 |
|
|
|
1841 |
|
|
if (res == ERR && change_scroll_region) { |
1842 |
|
|
if (top != 0 && (SP->_cursrow == top || SP->_cursrow == top - 1) |
1843 |
|
|
&& save_cursor && restore_cursor) { |
1844 |
|
|
cursor_saved = TRUE; |
1845 |
|
|
TPUTS_TRACE("save_cursor"); |
1846 |
|
|
putp(save_cursor); |
1847 |
|
|
} |
1848 |
|
|
TPUTS_TRACE("change_scroll_region"); |
1849 |
|
|
putp(TPARM_2(change_scroll_region, top, bot)); |
1850 |
|
|
if (cursor_saved) { |
1851 |
|
|
TPUTS_TRACE("restore_cursor"); |
1852 |
|
|
putp(restore_cursor); |
1853 |
|
|
} else { |
1854 |
|
|
SP->_cursrow = SP->_curscol = -1; |
1855 |
|
|
} |
1856 |
|
|
|
1857 |
|
|
res = scroll_csr_backward(-n, top, bot, top, bot, blank); |
1858 |
|
|
|
1859 |
|
|
TPUTS_TRACE("change_scroll_region"); |
1860 |
|
|
putp(TPARM_2(change_scroll_region, 0, maxy)); |
1861 |
|
|
SP->_cursrow = SP->_curscol = -1; |
1862 |
|
|
} |
1863 |
|
|
|
1864 |
|
|
if (res == ERR && _nc_idlok) |
1865 |
|
|
res = scroll_idl(-n, bot + n + 1, top, blank); |
1866 |
|
|
|
1867 |
|
|
/* |
1868 |
|
|
* Clear the newly shifted-in text. |
1869 |
|
|
*/ |
1870 |
|
|
if (res != ERR |
1871 |
|
|
&& (non_dest_scroll_region || (memory_above && top == 0))) { |
1872 |
|
|
static const NCURSES_CH_T blank2 = NewChar(BLANK_TEXT); |
1873 |
|
|
for (i = 0; i < -n; i++) { |
1874 |
|
|
GoTo(i + top, 0); |
1875 |
|
|
ClrToEOL(blank2, FALSE); |
1876 |
|
|
} |
1877 |
|
|
} |
1878 |
|
|
} |
1879 |
|
|
|
1880 |
|
|
if (res == ERR) |
1881 |
|
|
return (ERR); |
1882 |
|
|
|
1883 |
|
|
_nc_scroll_window(curscr, n, top, bot, blank); |
1884 |
|
|
|
1885 |
|
|
/* shift hash values too - they can be reused */ |
1886 |
|
|
_nc_scroll_oldhash(n, top, bot); |
1887 |
|
|
|
1888 |
|
|
return (OK); |
1889 |
|
|
} |
1890 |
|
|
|
1891 |
|
|
NCURSES_EXPORT(void) |
1892 |
|
|
_nc_screen_resume(void) |
1893 |
|
|
{ |
1894 |
|
|
/* make sure terminal is in a sane known state */ |
1895 |
|
|
SetAttr(SCREEN_ATTRS(SP), A_NORMAL); |
1896 |
|
|
newscr->_clear = TRUE; |
1897 |
|
|
|
1898 |
|
|
/* reset color pairs and definitions */ |
1899 |
|
|
if (SP->_coloron || SP->_color_defs) |
1900 |
|
|
_nc_reset_colors(); |
1901 |
|
|
|
1902 |
|
|
/* restore user-defined colors, if any */ |
1903 |
|
|
if (SP->_color_defs < 0) { |
1904 |
|
|
int n; |
1905 |
|
|
SP->_color_defs = -(SP->_color_defs); |
1906 |
|
|
for (n = 0; n < SP->_color_defs; ++n) { |
1907 |
|
|
if (SP->_color_table[n].init) { |
1908 |
|
|
init_color(n, |
1909 |
|
|
SP->_color_table[n].r, |
1910 |
|
|
SP->_color_table[n].g, |
1911 |
|
|
SP->_color_table[n].b); |
1912 |
|
|
} |
1913 |
|
|
} |
1914 |
|
|
} |
1915 |
|
|
|
1916 |
|
|
if (exit_attribute_mode) |
1917 |
|
|
putp(exit_attribute_mode); |
1918 |
|
|
else { |
1919 |
|
|
/* turn off attributes */ |
1920 |
|
|
if (exit_alt_charset_mode) |
1921 |
|
|
putp(exit_alt_charset_mode); |
1922 |
|
|
if (exit_standout_mode) |
1923 |
|
|
putp(exit_standout_mode); |
1924 |
|
|
if (exit_underline_mode) |
1925 |
|
|
putp(exit_underline_mode); |
1926 |
|
|
} |
1927 |
|
|
if (exit_insert_mode) |
1928 |
|
|
putp(exit_insert_mode); |
1929 |
|
|
if (enter_am_mode && exit_am_mode) |
1930 |
|
|
putp(auto_right_margin ? enter_am_mode : exit_am_mode); |
1931 |
|
|
} |
1932 |
|
|
|
1933 |
|
|
NCURSES_EXPORT(void) |
1934 |
|
|
_nc_screen_init(void) |
1935 |
|
|
{ |
1936 |
|
|
_nc_screen_resume(); |
1937 |
|
|
} |
1938 |
|
|
|
1939 |
|
|
/* wrap up screen handling */ |
1940 |
|
|
NCURSES_EXPORT(void) |
1941 |
|
|
_nc_screen_wrap(void) |
1942 |
|
|
{ |
1943 |
|
|
UpdateAttrs(normal); |
1944 |
|
|
#if NCURSES_EXT_FUNCS |
1945 |
|
|
if (SP->_coloron |
1946 |
|
|
&& !SP->_default_color) { |
1947 |
|
|
static const NCURSES_CH_T blank = NewChar(BLANK_TEXT); |
1948 |
|
|
SP->_default_color = TRUE; |
1949 |
|
|
_nc_do_color(-1, 0, FALSE, _nc_outch); |
1950 |
|
|
SP->_default_color = FALSE; |
1951 |
|
|
|
1952 |
|
|
mvcur(SP->_cursrow, SP->_curscol, screen_lines - 1, 0); |
1953 |
|
|
|
1954 |
|
|
ClrToEOL(blank, TRUE); |
1955 |
|
|
} |
1956 |
|
|
#endif |
1957 |
|
|
if (SP->_color_defs) { |
1958 |
|
|
_nc_reset_colors(); |
1959 |
|
|
} |
1960 |
|
|
} |
1961 |
|
|
|
1962 |
|
|
#if USE_XMC_SUPPORT |
1963 |
|
|
NCURSES_EXPORT(void) |
1964 |
|
|
_nc_do_xmc_glitch(attr_t previous) |
1965 |
|
|
{ |
1966 |
|
|
attr_t chg = XMC_CHANGES(previous ^ AttrOf(SCREEN_ATTRS(SP))); |
1967 |
|
|
|
1968 |
|
|
while (chg != 0) { |
1969 |
|
|
if (chg & 1) { |
1970 |
|
|
SP->_curscol += magic_cookie_glitch; |
1971 |
|
|
if (SP->_curscol >= SP->_columns) |
1972 |
|
|
wrap_cursor(); |
1973 |
|
|
TR(TRACE_UPDATE, ("bumped to %d,%d after cookie", SP->_cursrow, SP->_curscol)); |
1974 |
|
|
} |
1975 |
|
|
chg >>= 1; |
1976 |
|
|
} |
1977 |
|
|
} |
1978 |
|
|
#endif /* USE_XMC_SUPPORT */ |