(gdb_lisp_params): New enum type.
[bpt/emacs.git] / src / xdisp.c
CommitLineData
a2889657 1/* Display generation from window structure and buffer text.
5992c4f7 2 Copyright (C) 1985, 86, 87, 88, 93, 94, 95 Free Software Foundation, Inc.
a2889657
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
b1d1124b 8the Free Software Foundation; either version 2, or (at your option)
a2889657
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
18160b98 21#include <config.h>
a2889657
JB
22#include <stdio.h>
23/*#include <ctype.h>*/
24#undef NULL
25#include "lisp.h"
44fa5b1e 26#include "frame.h"
a2889657
JB
27#include "window.h"
28#include "termchar.h"
29#include "dispextern.h"
30#include "buffer.h"
31#include "indent.h"
32#include "commands.h"
33#include "macros.h"
34#include "disptab.h"
30c566e4 35#include "termhooks.h"
b0a0fbda 36#include "intervals.h"
a2889657 37
76412d64
RS
38#ifdef USE_X_TOOLKIT
39extern void set_frame_menubar ();
40#endif
41
a2889657
JB
42extern int interrupt_input;
43extern int command_loop_level;
44
c4628384
RS
45extern Lisp_Object Qface;
46
f88eb0b6 47/* Nonzero means print newline to stdout before next minibuffer message. */
a2889657
JB
48
49int noninteractive_need_newline;
50
f88eb0b6
KH
51/* Nonzero means print newline to message log before next message. */
52
3c6595e0 53static int message_log_need_newline;
f88eb0b6 54
a2889657
JB
55#define min(a, b) ((a) < (b) ? (a) : (b))
56#define max(a, b) ((a) > (b) ? (a) : (b))
210e752f
KH
57#define minmax(floor, val, ceil) \
58 ((val) < (floor) ? (floor) : (val) > (ceil) ? (ceil) : (val))
a2889657
JB
59
60/* The buffer position of the first character appearing
44fa5b1e
JB
61 entirely or partially on the current frame line.
62 Or zero, which disables the optimization for the current frame line. */
a2889657
JB
63static int this_line_bufpos;
64
65/* Number of characters past the end of this line,
66 including the terminating newline */
67static int this_line_endpos;
68
44fa5b1e 69/* The vertical position of this frame line. */
a2889657
JB
70static int this_line_vpos;
71
44fa5b1e 72/* Hpos value for start of display on this frame line.
a2889657
JB
73 Usually zero, but negative if first character really began
74 on previous line */
75static int this_line_start_hpos;
76
77/* Buffer that this_line variables are describing. */
78static struct buffer *this_line_buffer;
79
80/* Set by try_window_id to the vpos of first of any lines
44fa5b1e 81 scrolled on to the bottom of the frame. These lines should
a2889657
JB
82 not be included in any general scroll computation. */
83static int scroll_bottom_vpos;
84
85/* Value of echo_area_glyphs when it was last acted on.
44fa5b1e 86 If this is nonzero, there is a message on the frame
a2889657
JB
87 in the minibuffer and it should be erased as soon
88 as it is no longer requested to appear. */
89char *previous_echo_glyphs;
90
44fa5b1e 91/* Nonzero means truncate lines in all windows less wide than the frame */
a2889657
JB
92int truncate_partial_width_windows;
93
d39b6696
KH
94/* Nonzero means we have more than one non-minibuffer-only frame.
95 Not guaranteed to be accurate except while parsing frame-title-format. */
96int multiple_frames;
97
a2889657
JB
98Lisp_Object Vglobal_mode_string;
99
100/* Marker for where to display an arrow on top of the buffer text. */
101Lisp_Object Voverlay_arrow_position;
102
103/* String to display for the arrow. */
104Lisp_Object Voverlay_arrow_string;
105
d39b6696
KH
106/* Like mode-line-format, but for the titlebar on a visible frame. */
107Lisp_Object Vframe_title_format;
108
109/* Like mode-line-format, but for the titlebar on an iconified frame. */
110Lisp_Object Vicon_title_format;
111
08b610e4
RS
112/* List of functions to call when a window's size changes. These
113 functions get one arg, a frame on which one or more windows' sizes
114 have changed. */
115static Lisp_Object Vwindow_size_change_functions;
116
a2889657 117/* Values of those variables at last redisplay. */
ded34426 118static Lisp_Object last_arrow_position, last_arrow_string;
a2889657 119
cf074754
RS
120Lisp_Object Qmenu_bar_update_hook;
121
a2889657
JB
122/* Nonzero if overlay arrow has been displayed once in this window. */
123static int overlay_arrow_seen;
124
ca26e1c8
KH
125/* Nonzero if visible end of buffer has already been displayed once
126 in this window. (We need this variable in case there are overlay
127 strings that get displayed there.) */
128static int zv_strings_seen;
129
fba9ce76
RS
130/* Nonzero means highlight the region even in nonselected windows. */
131static int highlight_nonselected_windows;
132
44fa5b1e 133/* If cursor motion alone moves point off frame,
a2889657 134 Try scrolling this many lines up or down if that will bring it back. */
14510fee 135static int scroll_step;
a2889657
JB
136
137/* Nonzero if try_window_id has made blank lines at window bottom
138 since the last redisplay that paused */
139static int blank_end_of_window;
140
42640f83
RS
141/* Number of windows showing the buffer of the selected window
142 (or another buffer with the same base buffer).
a2889657
JB
143 keyboard.c refers to this. */
144int buffer_shared;
145
44fa5b1e 146/* display_text_line sets these to the frame position (origin 0) of point,
a2889657
JB
147 whether the window is selected or not.
148 Set one to -1 first to determine whether point was found afterwards. */
149
150static int cursor_vpos;
151static int cursor_hpos;
152
14510fee 153static int debug_end_pos;
a2889657
JB
154
155/* Nonzero means display mode line highlighted */
156int mode_line_inverse_video;
157
ff6c30e5 158static int message_log_check_duplicate ();
a2889657
JB
159static void echo_area_display ();
160void mark_window_display_accurate ();
161static void redisplay_windows ();
162static void redisplay_window ();
90adcf20 163static void update_menu_bar ();
a2889657
JB
164static void try_window ();
165static int try_window_id ();
166static struct position *display_text_line ();
167static void display_mode_line ();
168static int display_mode_element ();
169static char *fmodetrunc ();
170static char *decode_mode_spec ();
171static int display_string ();
7ce2c095 172static void display_menu_bar ();
aa6d10fa 173static int display_count_lines ();
a2889657
JB
174
175/* Prompt to display in front of the minibuffer contents */
8c5b6a0a 176Lisp_Object minibuf_prompt;
a2889657
JB
177
178/* Width in columns of current minibuffer prompt. */
179int minibuf_prompt_width;
180
181/* Message to display instead of minibuffer contents
182 This is what the functions error and message make,
183 and command echoing uses it as well.
184 It overrides the minibuf_prompt as well as the buffer. */
185char *echo_area_glyphs;
186
90adcf20
RS
187/* This is the length of the message in echo_area_glyphs. */
188int echo_area_glyphs_length;
189
a2889657
JB
190/* true iff we should redraw the mode lines on the next redisplay */
191int update_mode_lines;
192
193/* Smallest number of characters before the gap
194 at any time since last redisplay that finished.
195 Valid for current buffer when try_window_id can be called. */
196int beg_unchanged;
197
198/* Smallest number of characters after the gap
199 at any time since last redisplay that finished.
200 Valid for current buffer when try_window_id can be called. */
201int end_unchanged;
202
203/* MODIFF as of last redisplay that finished;
204 if it matches MODIFF, beg_unchanged and end_unchanged
205 contain no useful information */
206int unchanged_modified;
207
208/* Nonzero if head_clip or tail_clip of current buffer has changed
209 since last redisplay that finished */
210int clip_changed;
211
212/* Nonzero if window sizes or contents have changed
213 since last redisplay that finished */
214int windows_or_buffers_changed;
215
aa6d10fa
RS
216/* Nonzero after display_mode_line if %l was used
217 and it displayed a line number. */
218int line_number_displayed;
219
220/* Maximum buffer size for which to display line numbers. */
14510fee 221static int line_number_display_limit;
5992c4f7
KH
222
223/* Number of lines to keep in the message log buffer.
224 t means infinite. nil means don't log at all. */
225Lisp_Object Vmessage_log_max;
a2889657 226\f
3c6595e0
KH
227void
228message_log_maybe_newline ()
229{
230 if (message_log_need_newline)
231 message_dolog ("", 0, 1);
232}
233
234
d917be71
KH
235/* Add a string to the message log, optionally terminated with a newline.
236 This function calls low-level routines in order to bypass text property
237 hooks, etc. which might not be safe to run. */
90adcf20
RS
238
239void
f88eb0b6 240message_dolog (m, len, nlflag)
90adcf20 241 char *m;
f88eb0b6 242 int len, nlflag;
5992c4f7 243{
f88eb0b6 244 if (!NILP (Vmessage_log_max))
5992c4f7
KH
245 {
246 struct buffer *oldbuf;
247 int oldpoint, oldbegv, oldzv;
248
249 oldbuf = current_buffer;
3c6595e0 250 Fset_buffer (Fget_buffer_create (build_string ("*Messages*")));
16c300fb 251 current_buffer->undo_list = Qt;
5992c4f7
KH
252 oldpoint = PT;
253 oldbegv = BEGV;
254 oldzv = ZV;
d917be71
KH
255 BEGV = BEG;
256 ZV = Z;
5992c4f7 257 if (oldpoint == Z)
f88eb0b6 258 oldpoint += len + nlflag;
5992c4f7 259 if (oldzv == Z)
f88eb0b6 260 oldzv += len + nlflag;
5992c4f7 261 TEMP_SET_PT (Z);
f88eb0b6
KH
262 if (len)
263 insert_1 (m, len, 1, 0);
264 if (nlflag)
5992c4f7 265 {
ff6c30e5
KH
266 int this_bol, prev_bol, dup;
267 insert_1 ("\n", 1, 1, 0);
268
269 this_bol = scan_buffer ('\n', Z, 0, -2, 0, 0);
270 if (this_bol > BEG)
271 {
272 prev_bol = scan_buffer ('\n', this_bol, 0, -2, 0, 0);
273 dup = message_log_check_duplicate (prev_bol, this_bol);
274 if (dup)
275 {
276 if (oldpoint > prev_bol)
277 oldpoint -= min (this_bol, oldpoint) - prev_bol;
278 if (oldbegv > prev_bol)
279 oldbegv -= min (this_bol, oldbegv) - prev_bol;
280 if (oldzv > prev_bol)
281 oldzv -= min (this_bol, oldzv) - prev_bol;
282 del_range_1 (prev_bol, this_bol, 0);
283 if (dup > 1)
284 {
285 char dupstr[40];
286 int duplen;
287
288 /* If you change this format, don't forget to also
289 change message_log_check_duplicate. */
290 sprintf (dupstr, " [%d times]", dup);
291 duplen = strlen (dupstr);
292 TEMP_SET_PT (Z-1);
293 if (oldpoint == Z)
294 oldpoint += duplen;
295 if (oldzv == Z)
296 oldzv += duplen;
297 insert_1 (dupstr, duplen, 1, 0);
298 }
299 }
300 }
301
302 if (NATNUMP (Vmessage_log_max))
303 {
304 int pos = scan_buffer ('\n', Z, 0,
305 -XFASTINT (Vmessage_log_max) - 1, 0, 0);
306 oldpoint -= min (pos, oldpoint) - BEG;
307 oldbegv -= min (pos, oldbegv) - BEG;
308 oldzv -= min (pos, oldzv) - BEG;
309 del_range_1 (BEG, pos, 0);
310 }
5992c4f7
KH
311 }
312 BEGV = oldbegv;
313 ZV = oldzv;
314 TEMP_SET_PT (oldpoint);
315 set_buffer_internal (oldbuf);
3c6595e0 316 message_log_need_newline = !nlflag;
5992c4f7 317 }
f88eb0b6
KH
318}
319
320
ff6c30e5
KH
321/* We are at the end of the buffer after just having inserted a newline.
322 (Note: We depend on the fact we won't be crossing the gap.)
323 Check to see if the most recent message looks a lot like the previous one.
324 Return 0 if different, 1 if the new one should just replace it, or a
325 value N > 1 if we should also append " [N times]". */
f82aff7c 326
ff6c30e5
KH
327static int
328message_log_check_duplicate (prev_bol, this_bol)
329 int prev_bol, this_bol;
330{
331 int i;
332 int len = Z - 1 - this_bol;
333 int seen_dots = 0;
f82aff7c
RS
334 unsigned char *p1 = BUF_CHAR_ADDRESS (current_buffer, prev_bol);
335 unsigned char *p2 = BUF_CHAR_ADDRESS (current_buffer, this_bol);
ff6c30e5
KH
336
337 for (i = 0; i < len; i++)
338 {
339 if (i >= 3 && p1[i-3] == '.' && p1[i-2] == '.' && p1[i-1] == '.'
340 && p1[i] != '\n')
341 seen_dots = 1;
342 if (p1[i] != p2[i])
343 return seen_dots;
344 }
345 p1 += len;
346 if (*p1 == '\n')
347 return 2;
348 if (*p1++ == ' ' && *p1++ == '[')
349 {
350 int n = 0;
351 while (*p1 >= '0' && *p1 <= '9')
352 n = n * 10 + *p1++ - '0';
353 if (strncmp (p1, " times]\n", 8) == 0)
354 return n+1;
355 }
356 return 0;
357}
358
f88eb0b6
KH
359/* Display an echo area message M with a specified length of LEN chars.
360 The string may include null characters. If m is 0, clear out any
361 existing message, and let the minibuffer text show through.
362 Do not pass text that is stored in a Lisp string. */
363
364void
365message2 (m, len)
366 char *m;
367 int len;
368{
369 /* First flush out any partial line written with print. */
3c6595e0 370 message_log_maybe_newline ();
f88eb0b6
KH
371 if (m)
372 message_dolog (m, len, 1);
5992c4f7
KH
373 message2_nolog (m, len);
374}
375
376
377/* The non-logging part of that function. */
378
379void
380message2_nolog (m, len)
381 char *m;
382 int len;
90adcf20
RS
383{
384 if (noninteractive)
385 {
386 if (noninteractive_need_newline)
387 putc ('\n', stderr);
388 noninteractive_need_newline = 0;
389 fwrite (m, len, 1, stderr);
390 if (cursor_in_echo_area == 0)
391 fprintf (stderr, "\n");
392 fflush (stderr);
393 }
394 /* A null message buffer means that the frame hasn't really been
395 initialized yet. Error messages get reported properly by
396 cmd_error, so this must be just an informative message; toss it. */
397 else if (INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame))
398 {
399#ifdef MULTI_FRAME
400 Lisp_Object minibuf_frame;
401
402 choose_minibuf_frame ();
403 minibuf_frame = WINDOW_FRAME (XWINDOW (minibuf_window));
404 FRAME_SAMPLE_VISIBILITY (XFRAME (minibuf_frame));
405 if (FRAME_VISIBLE_P (selected_frame)
406 && ! FRAME_VISIBLE_P (XFRAME (minibuf_frame)))
407 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (minibuf_window)));
408#endif
409
410 if (m)
411 {
412 echo_area_glyphs = m;
413 echo_area_glyphs_length = len;
414 }
ded34426
JB
415 else
416 echo_area_glyphs = previous_echo_glyphs = 0;
417
418 do_pending_window_change ();
419 echo_area_display ();
420 update_frame (XFRAME (XWINDOW (minibuf_window)->frame), 1, 1);
421 do_pending_window_change ();
853cf346
RS
422 if (frame_up_to_date_hook != 0 && ! gc_in_progress)
423 (*frame_up_to_date_hook) (XFRAME (XWINDOW (minibuf_window)->frame));
ded34426
JB
424 }
425}
426
48ae5f0a
KH
427void
428message1 (m)
429 char *m;
430{
431 message2 (m, (m ? strlen (m) : 0));
432}
433
0b1005ef
KH
434void
435message1_nolog (m)
436 char *m;
437{
438 message2_nolog (m, (m ? strlen (m) : 0));
439}
440
76412d64
RS
441/* Truncate what will be displayed in the echo area
442 the next time we display it--but don't redisplay it now. */
443
444void
445truncate_echo_area (len)
446 int len;
447{
448 /* A null message buffer means that the frame hasn't really been
449 initialized yet. Error messages get reported properly by
450 cmd_error, so this must be just an informative message; toss it. */
451 if (!noninteractive && INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame))
452 echo_area_glyphs_length = len;
453}
454
44fa5b1e 455/* Nonzero if FRAME_MESSAGE_BUF (selected_frame) is being used by print;
9c74a0dd
JB
456 zero if being used by message. */
457int message_buf_print;
458
81d478f3
JB
459/* Dump an informative message to the minibuf. If m is 0, clear out
460 any existing message, and let the minibuffer text show through. */
a2889657 461/* VARARGS 1 */
a2889657
JB
462void
463message (m, a1, a2, a3)
464 char *m;
5d5ed907 465 EMACS_INT a1, a2, a3;
a2889657
JB
466{
467 if (noninteractive)
468 {
81d478f3
JB
469 if (m)
470 {
471 if (noninteractive_need_newline)
472 putc ('\n', stderr);
473 noninteractive_need_newline = 0;
474 fprintf (stderr, m, a1, a2, a3);
c4f14ccb
RS
475 if (cursor_in_echo_area == 0)
476 fprintf (stderr, "\n");
81d478f3
JB
477 fflush (stderr);
478 }
a2889657 479 }
1f40cad2 480 else if (INTERACTIVE)
a2889657 481 {
1f40cad2
JB
482 /* The frame whose minibuffer we're going to display the message on.
483 It may be larger than the selected frame, so we need
484 to use its buffer, not the selected frame's buffer. */
485 FRAME_PTR echo_frame;
486#ifdef MULTI_FRAME
487 choose_minibuf_frame ();
488 echo_frame = XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
489#else
490 echo_frame = selected_frame;
491#endif
492
493 /* A null message buffer means that the frame hasn't really been
494 initialized yet. Error messages get reported properly by
495 cmd_error, so this must be just an informative message; toss it. */
496 if (FRAME_MESSAGE_BUF (echo_frame))
81d478f3 497 {
1f40cad2
JB
498 if (m)
499 {
90adcf20 500 int len;
a2889657 501#ifdef NO_ARG_ARRAY
5d5ed907 502 EMACS_INT a[3];
90adcf20
RS
503 a[0] = a1;
504 a[1] = a2;
505 a[2] = a3;
a2889657 506
90adcf20
RS
507 len = doprnt (FRAME_MESSAGE_BUF (echo_frame),
508 FRAME_WIDTH (echo_frame), m, 0, 3, a);
a2889657 509#else
90adcf20
RS
510 len = doprnt (FRAME_MESSAGE_BUF (echo_frame),
511 FRAME_WIDTH (echo_frame), m, 0, 3, &a1);
1f40cad2 512#endif /* NO_ARG_ARRAY */
1f40cad2 513
90adcf20 514 message2 (FRAME_MESSAGE_BUF (echo_frame), len);
1f40cad2
JB
515 }
516 else
517 message1 (0);
518
519 /* Print should start at the beginning of the message
520 buffer next time. */
521 message_buf_print = 0;
81d478f3 522 }
a2889657
JB
523 }
524}
525
6c4429a5
KH
526/* The non-logging version of that function. */
527void
528message_nolog (m, a1, a2, a3)
529 char *m;
530 EMACS_INT a1, a2, a3;
531{
532 Lisp_Object old_log_max;
533 old_log_max = Vmessage_log_max;
534 Vmessage_log_max = Qnil;
535 message (m, a1, a2, a3);
536 Vmessage_log_max = old_log_max;
537}
538
131f2133
RS
539void
540update_echo_area ()
541{
542 message2 (echo_area_glyphs, echo_area_glyphs_length);
543}
544
a2889657
JB
545static void
546echo_area_display ()
547{
548 register int vpos;
44fa5b1e 549 FRAME_PTR f;
a2889657 550
44fa5b1e
JB
551#ifdef MULTI_FRAME
552 choose_minibuf_frame ();
b1d1124b
JB
553#endif
554
44fa5b1e 555 f = XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
a2889657 556
44fa5b1e 557 if (! FRAME_VISIBLE_P (f))
a2889657 558 return;
a2889657 559
44fa5b1e 560 if (frame_garbaged)
a2889657 561 {
02a9b6e4 562 redraw_garbaged_frames ();
44fa5b1e 563 frame_garbaged = 0;
a2889657
JB
564 }
565
566 if (echo_area_glyphs || minibuf_level == 0)
567 {
568 vpos = XFASTINT (XWINDOW (minibuf_window)->top);
44fa5b1e 569 get_display_line (f, vpos, 0);
a2889657
JB
570 display_string (XWINDOW (minibuf_window), vpos,
571 echo_area_glyphs ? echo_area_glyphs : "",
90adcf20 572 echo_area_glyphs ? echo_area_glyphs_length : -1,
278feba9 573 0, 0, 0, 0, FRAME_WIDTH (f));
a2889657
JB
574
575 /* If desired cursor location is on this line, put it at end of text */
b5bbc9a5
KH
576 if (cursor_in_echo_area)
577 FRAME_CURSOR_Y (f) = vpos;
44fa5b1e
JB
578 if (FRAME_CURSOR_Y (f) == vpos)
579 FRAME_CURSOR_X (f) = FRAME_DESIRED_GLYPHS (f)->used[vpos];
daa37602
JB
580
581 /* Fill the rest of the minibuffer window with blank lines. */
582 {
583 int i;
584
b2a76982
RS
585 for (i = vpos + 1;
586 i < vpos + XFASTINT (XWINDOW (minibuf_window)->height); i++)
daa37602 587 {
44fa5b1e 588 get_display_line (f, i, 0);
daa37602 589 display_string (XWINDOW (minibuf_window), vpos,
278feba9 590 "", 0, 0, 0, 0, 0, FRAME_WIDTH (f));
daa37602
JB
591 }
592 }
a2889657
JB
593 }
594 else if (!EQ (minibuf_window, selected_window))
595 windows_or_buffers_changed++;
596
597 if (EQ (minibuf_window, selected_window))
598 this_line_bufpos = 0;
599
600 previous_echo_glyphs = echo_area_glyphs;
601}
96a410bc
KH
602
603#ifdef HAVE_X_WINDOWS
d39b6696
KH
604static char frame_title_buf[512];
605static char *frame_title_ptr;
96a410bc 606
d39b6696
KH
607static int
608store_frame_title (str, mincol, maxcol)
609 char *str;
610 int mincol, maxcol;
611{
612 char *limit;
613 if (maxcol < 0 || maxcol >= sizeof(frame_title_buf))
614 maxcol = sizeof (frame_title_buf);
615 limit = &frame_title_buf[maxcol];
616 while (*str != '\0' && frame_title_ptr < limit)
617 *frame_title_ptr++ = *str++;
618 while (frame_title_ptr < &frame_title_buf[mincol])
619 *frame_title_ptr++ = ' ';
620 return frame_title_ptr - frame_title_buf;
621}
96a410bc 622
96a410bc
KH
623static void
624x_consider_frame_title (frame)
625 Lisp_Object frame;
626{
d39b6696
KH
627 Lisp_Object fmt;
628 struct buffer *obuf;
629 int len;
96a410bc
KH
630 FRAME_PTR f = XFRAME (frame);
631
d39b6696
KH
632 if (!FRAME_X_P (f) || FRAME_MINIBUF_ONLY_P (f) || f->explicit_name)
633 return;
3450d04c
KH
634
635 /* Do we have more than one visible frame on this X display? */
636 {
637 Lisp_Object tail;
638
639 for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
640 {
641 FRAME_PTR tf = XFRAME (XCONS (tail)->car);
642
643 if (tf != f && tf->kboard == f->kboard && !FRAME_MINIBUF_ONLY_P (tf)
644 && (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf)))
645 break;
646 }
647
648 multiple_frames = CONSP (tail);
649 }
650
d39b6696
KH
651 obuf = current_buffer;
652 Fset_buffer (XWINDOW (f->selected_window)->buffer);
653 fmt = (FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format);
654 frame_title_ptr = frame_title_buf;
655 len = display_mode_element (XWINDOW (f->selected_window), 0, 0, 0,
656 0, sizeof (frame_title_buf), fmt);
657 frame_title_ptr = 0;
658 set_buffer_internal (obuf);
659 /* Set the name only if it's changed. This avoids consing
660 in the common case where it hasn't. (If it turns out that we've
661 already wasted too much time by walking through the list with
662 display_mode_element, then we might need to optimize at a higher
663 level than this.) */
664 if (! STRINGP (f->name) || XSTRING (f->name)->size != len
665 || bcmp (frame_title_buf, XSTRING (f->name)->data, len) != 0)
666 x_implicitly_set_name (f, make_string (frame_title_buf, len), Qnil);
96a410bc 667}
c7c9ca97
KH
668#else
669#define frame_title_ptr ((char *)0)
e39322d9 670#define store_frame_title(str, mincol, maxcol) 0
96a410bc 671#endif
a2889657 672\f
90adcf20 673/* Prepare for redisplay by updating menu-bar item lists when appropriate.
87382820 674 This can call eval. */
90adcf20
RS
675
676void
677prepare_menu_bars ()
678{
679 register struct window *w = XWINDOW (selected_window);
680 int all_windows;
08b610e4 681 struct gcpro gcpro1, gcpro2;
90adcf20 682
ecf7de9b
RS
683 all_windows = (update_mode_lines || buffer_shared > 1
684 || clip_changed || windows_or_buffers_changed);
90adcf20
RS
685
686 /* Update the menu bar item lists, if appropriate.
687 This has to be done before any actual redisplay
688 or generation of display lines. */
689 if (all_windows)
690 {
691 Lisp_Object tail, frame;
a2725ab2
RS
692 int count = specpdl_ptr - specpdl;
693
694 record_unwind_protect (Fstore_match_data, Fmatch_data ());
90adcf20
RS
695
696 FOR_EACH_FRAME (tail, frame)
08b610e4
RS
697 {
698 /* If a window on this frame changed size,
699 report that to the user and clear the size-change flag. */
700 if (FRAME_WINDOW_SIZES_CHANGED (XFRAME (frame)))
701 {
702 Lisp_Object functions;
14510fee
RS
703 /* Clear flag first in case we get error below. */
704 FRAME_WINDOW_SIZES_CHANGED (XFRAME (frame)) = 0;
08b610e4
RS
705 functions = Vwindow_size_change_functions;
706 GCPRO2 (tail, functions);
707 while (CONSP (functions))
708 {
709 call1 (XCONS (functions)->car, frame);
710 functions = XCONS (functions)->cdr;
711 }
712 UNGCPRO;
08b610e4
RS
713 }
714 GCPRO1 (tail);
a2725ab2 715 update_menu_bar (XFRAME (frame), 0);
08b610e4
RS
716 UNGCPRO;
717 }
a2725ab2
RS
718
719 unbind_to (count, Qnil);
90adcf20 720 }
ecf7de9b 721 else
a2725ab2 722 update_menu_bar (selected_frame, 1);
ab2f96f8
RS
723
724 /* Update all frame titles based on their buffer names, etc.
725 We do this after the menu bars so that the frame will first
726 create its menu bar using the name `emacs' if no other name
727 has yet been specified. */
728#ifdef HAVE_X_WINDOWS
729 if (windows_or_buffers_changed)
730 {
731 Lisp_Object tail, frame;
732
733 FOR_EACH_FRAME (tail, frame)
734 if (FRAME_VISIBLE_P (XFRAME (frame))
735 || FRAME_ICONIFIED_P (XFRAME (frame)))
736 x_consider_frame_title (frame);
737 }
738#endif
90adcf20
RS
739}
740\f
44fa5b1e 741/* Do a frame update, taking possible shortcuts into account.
a2889657
JB
742 This is the main external entry point for redisplay.
743
744 If the last redisplay displayed an echo area message and that
745 message is no longer requested, we clear the echo area
746 or bring back the minibuffer if that is in use.
747
90adcf20
RS
748 Do not call eval from within this function.
749 Calls to eval after the call to echo_area_display would confuse
750 the display_line mechanism and would cause a crash.
751 Calls to eval before that point will work most of the time,
752 but can still lose, because this function
753 can be called from signal handlers; with alarms set up;
a2889657 754 or with synchronous processes running.
90adcf20 755
a2889657
JB
756 See Fcall_process; if you called it from here, it could be
757 entered recursively. */
758
0d231165
RS
759static int do_verify_charstarts;
760
463f6b91
RS
761/* Counter is used to clear the face cache
762 no more than once ever 1000 redisplays. */
763static int clear_face_cache_count;
764
a2889657
JB
765void
766redisplay ()
767{
768 register struct window *w = XWINDOW (selected_window);
769 register int pause;
770 int must_finish = 0;
771 int all_windows;
772 register int tlbufpos, tlendpos;
773 struct position pos;
a2889657
JB
774
775 if (noninteractive)
776 return;
777
d724d989
JB
778 /* Set the visible flags for all frames.
779 Do this before checking for resized or garbaged frames; they want
780 to know if their frames are visible.
781 See the comment in frame.h for FRAME_SAMPLE_VISIBILITY. */
782 {
35f56f96 783 Lisp_Object tail, frame;
d724d989 784
35f56f96 785 FOR_EACH_FRAME (tail, frame)
f82aff7c
RS
786 {
787 FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
788
789 /* Clear out all the display lines in which we will generate the
790 glyphs to display. */
791 init_desired_glyphs (XFRAME (frame));
792 }
d724d989
JB
793 }
794
44fa5b1e 795 /* Notice any pending interrupt request to change frame size. */
a2889657
JB
796 do_pending_window_change ();
797
44fa5b1e 798 if (frame_garbaged)
a2889657 799 {
02a9b6e4 800 redraw_garbaged_frames ();
44fa5b1e 801 frame_garbaged = 0;
a2889657
JB
802 }
803
f82aff7c
RS
804 prepare_menu_bars ();
805
155ef550
KH
806 if (clip_changed || windows_or_buffers_changed
807 || (!NILP (w->column_number_displayed)
808 && XFASTINT (w->column_number_displayed) != current_column ()))
a2889657
JB
809 update_mode_lines++;
810
811 /* Detect case that we need to write a star in the mode line. */
812 if (XFASTINT (w->last_modified) < MODIFF
42640f83 813 && XFASTINT (w->last_modified) <= SAVE_MODIFF)
a2889657
JB
814 {
815 w->update_mode_line = Qt;
816 if (buffer_shared > 1)
817 update_mode_lines++;
818 }
819
44fa5b1e 820 FRAME_SCROLL_BOTTOM_VPOS (XFRAME (w->frame)) = -1;
a2889657
JB
821
822 all_windows = update_mode_lines || buffer_shared > 1;
a2889657
JB
823
824 /* If specs for an arrow have changed, do thorough redisplay
825 to ensure we remove any arrow that should no longer exist. */
ded34426
JB
826 if (! EQ (Voverlay_arrow_position, last_arrow_position)
827 || ! EQ (Voverlay_arrow_string, last_arrow_string))
a2889657
JB
828 all_windows = 1, clip_changed = 1;
829
90adcf20
RS
830 /* Normally the message* functions will have already displayed and
831 updated the echo area, but the frame may have been trashed, or
832 the update may have been preempted, so display the echo area
833 again here. */
834 if (echo_area_glyphs || previous_echo_glyphs)
835 {
836 echo_area_display ();
837 must_finish = 1;
838 }
839
bd66d1ba
RS
840 /* If showing region, and mark has changed, must redisplay whole window. */
841 if (((!NILP (Vtransient_mark_mode)
842 && !NILP (XBUFFER (w->buffer)->mark_active))
843 != !NILP (w->region_showing))
82d04750
JB
844 || (!NILP (w->region_showing)
845 && !EQ (w->region_showing,
846 Fmarker_position (XBUFFER (w->buffer)->mark))))
bd66d1ba
RS
847 this_line_bufpos = -1;
848
a2889657
JB
849 tlbufpos = this_line_bufpos;
850 tlendpos = this_line_endpos;
265a9e55 851 if (!all_windows && tlbufpos > 0 && NILP (w->update_mode_line)
44fa5b1e 852 && FRAME_VISIBLE_P (XFRAME (w->frame))
a2889657
JB
853 /* Make sure recorded data applies to current buffer, etc */
854 && this_line_buffer == current_buffer
855 && current_buffer == XBUFFER (w->buffer)
265a9e55 856 && NILP (w->force_start)
a2889657 857 /* Point must be on the line that we have info recorded about */
ae3b1442
KH
858 && PT >= tlbufpos
859 && PT <= Z - tlendpos
a2889657
JB
860 /* All text outside that line, including its final newline,
861 must be unchanged */
862 && (XFASTINT (w->last_modified) >= MODIFF
863 || (beg_unchanged >= tlbufpos - 1
864 && GPT >= tlbufpos
05ba02eb
JB
865 /* If selective display, can't optimize
866 if the changes start at the beginning of the line. */
e24c997d 867 && ((INTEGERP (current_buffer->selective_display)
05ba02eb
JB
868 && XINT (current_buffer->selective_display) > 0
869 ? (beg_unchanged >= tlbufpos
870 && GPT > tlbufpos)
871 : 1))
a2889657
JB
872 && end_unchanged >= tlendpos
873 && Z - GPT >= tlendpos)))
874 {
875 if (tlbufpos > BEGV && FETCH_CHAR (tlbufpos - 1) != '\n'
876 && (tlbufpos == ZV
877 || FETCH_CHAR (tlbufpos) == '\n'))
878 /* Former continuation line has disappeared by becoming empty */
879 goto cancel;
880 else if (XFASTINT (w->last_modified) < MODIFF
881 || MINI_WINDOW_P (w))
882 {
883 cursor_vpos = -1;
884 overlay_arrow_seen = 0;
ca26e1c8 885 zv_strings_seen = 0;
a2889657
JB
886 display_text_line (w, tlbufpos, this_line_vpos, this_line_start_hpos,
887 pos_tab_offset (w, tlbufpos));
888 /* If line contains point, is not continued,
889 and ends at same distance from eob as before, we win */
890 if (cursor_vpos >= 0 && this_line_bufpos
891 && this_line_endpos == tlendpos)
892 {
0d231165
RS
893 /* If this is not the window's last line,
894 we must adjust the charstarts of the lines below. */
895 if (this_line_vpos + 1
896 < XFASTINT (w->top) + window_internal_height (w))
85bcef6c
RS
897 {
898 int left = XFASTINT (w->left);
899 int *charstart_next_line
900 = FRAME_CURRENT_GLYPHS (XFRAME (WINDOW_FRAME (w)))->charstarts[this_line_vpos + 1];
85bcef6c
RS
901 int adjust;
902
903 if (Z - tlendpos == ZV)
904 /* This line ends at end of (accessible part of) buffer.
905 There is no newline to count. */
906 adjust = Z - tlendpos - charstart_next_line[left];
907 else
908 /* This line ends in a newline.
909 Must take account of the newline and the rest of the
910 text that follows. */
911 adjust = Z - tlendpos + 1 - charstart_next_line[left];
912
913 adjust_window_charstarts (w, this_line_vpos, adjust);
914 }
46db8486 915
44fa5b1e 916 if (XFASTINT (w->width) != FRAME_WIDTH (XFRAME (WINDOW_FRAME (w))))
a2889657
JB
917 preserve_other_columns (w);
918 goto update;
919 }
920 else
921 goto cancel;
922 }
ae3b1442 923 else if (PT == XFASTINT (w->last_point))
a2889657
JB
924 {
925 if (!must_finish)
926 {
927 do_pending_window_change ();
928 return;
929 }
930 goto update;
931 }
8b51f1e3
KH
932 /* If highlighting the region, or if the cursor is in the echo area,
933 then we can't just move the cursor. */
bd66d1ba
RS
934 else if (! (!NILP (Vtransient_mark_mode)
935 && !NILP (current_buffer->mark_active))
8b51f1e3
KH
936 && NILP (w->region_showing)
937 && !cursor_in_echo_area)
a2889657
JB
938 {
939 pos = *compute_motion (tlbufpos, 0,
940 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
ca26e1c8 941 0,
ae3b1442 942 PT, 2, - (1 << (SHORTBITS - 1)),
b1d1124b 943 window_internal_width (w) - 1,
de3e8b15 944 XINT (w->hscroll),
e37f06d7 945 pos_tab_offset (w, tlbufpos), w);
a2889657
JB
946 if (pos.vpos < 1)
947 {
210e752f 948 int width = window_internal_width (w) - 1;
44fa5b1e 949 FRAME_CURSOR_X (selected_frame)
210e752f 950 = XFASTINT (w->left) + minmax (0, pos.hpos, width);
44fa5b1e 951 FRAME_CURSOR_Y (selected_frame) = this_line_vpos;
a2889657
JB
952 goto update;
953 }
954 else
955 goto cancel;
956 }
957 cancel:
958 /* Text changed drastically or point moved off of line */
44fa5b1e 959 cancel_line (this_line_vpos, selected_frame);
a2889657
JB
960 }
961
962 this_line_bufpos = 0;
963 all_windows |= buffer_shared > 1;
964
463f6b91
RS
965 clear_face_cache_count++;
966
a2889657
JB
967 if (all_windows)
968 {
35f56f96 969 Lisp_Object tail, frame;
a2889657 970
87485d6f 971#ifdef HAVE_FACES
463f6b91
RS
972 /* Clear the face cache, only when we do a full redisplay
973 and not too often either. */
974 if (clear_face_cache_count > 1000)
975 {
976 clear_face_cache ();
977 clear_face_cache_count = 0;
978 }
31b24551
JB
979#endif
980
a2889657 981 /* Recompute # windows showing selected buffer.
8de2d90b 982 This will be incremented each time such a window is displayed. */
a2889657
JB
983 buffer_shared = 0;
984
35f56f96 985 FOR_EACH_FRAME (tail, frame)
30c566e4 986 {
35f56f96 987 FRAME_PTR f = XFRAME (frame);
9769686d
RS
988 if (! FRAME_TERMCAP_P (f) || f == selected_frame)
989 {
35f56f96 990
9769686d
RS
991 /* Mark all the scroll bars to be removed; we'll redeem the ones
992 we want when we redisplay their windows. */
993 if (condemn_scroll_bars_hook)
994 (*condemn_scroll_bars_hook) (f);
30c566e4 995
9769686d
RS
996 if (FRAME_VISIBLE_P (f))
997 redisplay_windows (FRAME_ROOT_WINDOW (f));
30c566e4 998
9769686d
RS
999 /* Any scroll bars which redisplay_windows should have nuked
1000 should now go away. */
1001 if (judge_scroll_bars_hook)
1002 (*judge_scroll_bars_hook) (f);
1003 }
30c566e4 1004 }
a2889657 1005 }
44fa5b1e 1006 else if (FRAME_VISIBLE_P (selected_frame))
a2889657
JB
1007 {
1008 redisplay_window (selected_window, 1);
44fa5b1e 1009 if (XFASTINT (w->width) != FRAME_WIDTH (selected_frame))
a2889657
JB
1010 preserve_other_columns (w);
1011 }
1012
1013update:
1014 /* Prevent various kinds of signals during display update.
1015 stdio is not robust about handling signals,
1016 which can cause an apparent I/O error. */
1017 if (interrupt_input)
1018 unrequest_sigio ();
1019 stop_polling ();
1020
44fa5b1e 1021#ifdef MULTI_FRAME
a2889657
JB
1022 if (all_windows)
1023 {
1024 Lisp_Object tail;
1025
1026 pause = 0;
1027
44fa5b1e 1028 for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
a2889657 1029 {
44fa5b1e 1030 FRAME_PTR f;
a2889657 1031
e24c997d 1032 if (!FRAMEP (XCONS (tail)->car))
a2889657
JB
1033 continue;
1034
44fa5b1e 1035 f = XFRAME (XCONS (tail)->car);
1af9f229
RS
1036
1037 if ((! FRAME_TERMCAP_P (f) || f == selected_frame)
1038 && FRAME_VISIBLE_P (f))
a2889657 1039 {
44fa5b1e 1040 pause |= update_frame (f, 0, 0);
a2889657 1041 if (!pause)
efc63ef0
RS
1042 {
1043 mark_window_display_accurate (f->root_window, 1);
1044 if (frame_up_to_date_hook != 0)
1045 (*frame_up_to_date_hook) (f);
1046 }
a2889657
JB
1047 }
1048 }
1049 }
1050 else
44fa5b1e 1051#endif /* MULTI_FRAME */
6e8290aa 1052 {
44fa5b1e
JB
1053 if (FRAME_VISIBLE_P (selected_frame))
1054 pause = update_frame (selected_frame, 0, 0);
4d641a15
KH
1055 else
1056 pause = 0;
d724d989 1057
8de2d90b 1058 /* We may have called echo_area_display at the top of this
44fa5b1e
JB
1059 function. If the echo area is on another frame, that may
1060 have put text on a frame other than the selected one, so the
1061 above call to update_frame would not have caught it. Catch
8de2d90b
JB
1062 it here. */
1063 {
efc63ef0
RS
1064 FRAME_PTR mini_frame
1065 = XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
8de2d90b 1066
44fa5b1e
JB
1067 if (mini_frame != selected_frame)
1068 pause |= update_frame (mini_frame, 0, 0);
8de2d90b 1069 }
6e8290aa 1070 }
a2889657 1071
44fa5b1e 1072 /* If frame does not match, prevent doing single-line-update next time.
a2889657
JB
1073 Also, don't forget to check every line to update the arrow. */
1074 if (pause)
1075 {
1076 this_line_bufpos = 0;
265a9e55 1077 if (!NILP (last_arrow_position))
a2889657
JB
1078 {
1079 last_arrow_position = Qt;
1080 last_arrow_string = Qt;
1081 }
44fa5b1e 1082 /* If we pause after scrolling, some lines in current_frame
a2889657
JB
1083 may be null, so preserve_other_columns won't be able to
1084 preserve all the vertical-bar separators. So, avoid using it
1085 in that case. */
44fa5b1e 1086 if (XFASTINT (w->width) != FRAME_WIDTH (selected_frame))
a2889657
JB
1087 update_mode_lines = 1;
1088 }
1089
44fa5b1e 1090 /* Now text on frame agrees with windows, so
a2889657
JB
1091 put info into the windows for partial redisplay to follow */
1092
1093 if (!pause)
1094 {
1095 register struct buffer *b = XBUFFER (w->buffer);
1096
1097 blank_end_of_window = 0;
1098 clip_changed = 0;
1099 unchanged_modified = BUF_MODIFF (b);
1100 beg_unchanged = BUF_GPT (b) - BUF_BEG (b);
1101 end_unchanged = BUF_Z (b) - BUF_GPT (b);
1102
c2213350
KH
1103 XSETFASTINT (w->last_point, BUF_PT (b));
1104 XSETFASTINT (w->last_point_x, FRAME_CURSOR_X (selected_frame));
1105 XSETFASTINT (w->last_point_y, FRAME_CURSOR_Y (selected_frame));
a2889657
JB
1106
1107 if (all_windows)
11e82b76 1108 mark_window_display_accurate (FRAME_ROOT_WINDOW (selected_frame), 1);
a2889657
JB
1109 else
1110 {
1111 w->update_mode_line = Qnil;
c2213350 1112 XSETFASTINT (w->last_modified, BUF_MODIFF (b));
d2f84654 1113 w->window_end_valid = w->buffer;
a2889657
JB
1114 last_arrow_position = Voverlay_arrow_position;
1115 last_arrow_string = Voverlay_arrow_string;
0d231165
RS
1116 if (do_verify_charstarts)
1117 verify_charstarts (w);
efc63ef0
RS
1118 if (frame_up_to_date_hook != 0)
1119 (*frame_up_to_date_hook) (selected_frame);
a2889657
JB
1120 }
1121 update_mode_lines = 0;
1122 windows_or_buffers_changed = 0;
1123 }
1124
1125 /* Start SIGIO interrupts coming again.
1126 Having them off during the code above
1127 makes it less likely one will discard output,
1128 but not impossible, since there might be stuff
1129 in the system buffer here.
1130 But it is much hairier to try to do anything about that. */
1131
1132 if (interrupt_input)
1133 request_sigio ();
1134 start_polling ();
1135
44fa5b1e 1136 /* Change frame size now if a change is pending. */
a2889657 1137 do_pending_window_change ();
d8e242fd
RS
1138
1139 /* If we just did a pending size change, redisplay again
1140 for the new size. */
3c8c72e0 1141 if (windows_or_buffers_changed && !pause)
d8e242fd 1142 redisplay ();
a2889657
JB
1143}
1144
1145/* Redisplay, but leave alone any recent echo area message
1146 unless another message has been requested in its place.
1147
1148 This is useful in situations where you need to redisplay but no
1149 user action has occurred, making it inappropriate for the message
1150 area to be cleared. See tracking_off and
1151 wait_reading_process_input for examples of these situations. */
1152
1153redisplay_preserve_echo_area ()
1154{
1155 if (echo_area_glyphs == 0 && previous_echo_glyphs != 0)
1156 {
1157 echo_area_glyphs = previous_echo_glyphs;
1158 redisplay ();
1159 echo_area_glyphs = 0;
1160 }
1161 else
1162 redisplay ();
1163}
1164
1165void
1166mark_window_display_accurate (window, flag)
1167 Lisp_Object window;
1168 int flag;
1169{
1170 register struct window *w;
1171
265a9e55 1172 for (;!NILP (window); window = w->next)
a2889657 1173 {
e24c997d 1174 if (!WINDOWP (window)) abort ();
a2889657
JB
1175 w = XWINDOW (window);
1176
265a9e55 1177 if (!NILP (w->buffer))
bd66d1ba 1178 {
c2213350
KH
1179 XSETFASTINT (w->last_modified,
1180 !flag ? 0 : BUF_MODIFF (XBUFFER (w->buffer)));
bd66d1ba
RS
1181
1182 /* Record if we are showing a region, so can make sure to
1183 update it fully at next redisplay. */
1184 w->region_showing = (!NILP (Vtransient_mark_mode)
1185 && !NILP (XBUFFER (w->buffer)->mark_active)
1186 ? Fmarker_position (XBUFFER (w->buffer)->mark)
1187 : Qnil);
1188 }
1189
d2f84654 1190 w->window_end_valid = w->buffer;
a2889657
JB
1191 w->update_mode_line = Qnil;
1192
265a9e55 1193 if (!NILP (w->vchild))
a2889657 1194 mark_window_display_accurate (w->vchild, flag);
265a9e55 1195 if (!NILP (w->hchild))
a2889657
JB
1196 mark_window_display_accurate (w->hchild, flag);
1197 }
1198
1199 if (flag)
1200 {
1201 last_arrow_position = Voverlay_arrow_position;
1202 last_arrow_string = Voverlay_arrow_string;
1203 }
1204 else
1205 {
1206 /* t is unequal to any useful value of Voverlay_arrow_... */
1207 last_arrow_position = Qt;
1208 last_arrow_string = Qt;
1209 }
1210}
1211\f
ecf7de9b 1212/* Update the menu bar item list for frame F.
90adcf20 1213 This has to be done before we start to fill in any display lines,
a2725ab2
RS
1214 because it can call eval.
1215
1216 If SAVE_MATCH_DATA is 1, we must save and restore it here. */
90adcf20
RS
1217
1218static void
a2725ab2 1219update_menu_bar (f, save_match_data)
ecf7de9b 1220 FRAME_PTR f;
a2725ab2 1221 int save_match_data;
90adcf20 1222{
90adcf20 1223 struct buffer *old = current_buffer;
ecf7de9b
RS
1224 Lisp_Object window;
1225 register struct window *w;
a2725ab2 1226
ecf7de9b
RS
1227 window = FRAME_SELECTED_WINDOW (f);
1228 w = XWINDOW (window);
90adcf20
RS
1229
1230 if (update_mode_lines)
1231 w->update_mode_line = Qt;
1232
cf074754 1233 if (
78614721 1234#ifdef USE_X_TOOLKIT
cf074754 1235 FRAME_EXTERNAL_MENU_BAR (f)
78614721 1236#else
cf074754 1237 FRAME_MENU_BAR_LINES (f) > 0
78614721 1238#endif
ecf7de9b 1239 )
90adcf20
RS
1240 {
1241 /* If the user has switched buffers or windows, we need to
1242 recompute to reflect the new bindings. But we'll
1243 recompute when update_mode_lines is set too; that means
1244 that people can use force-mode-line-update to request
1245 that the menu bar be recomputed. The adverse effect on
1246 the rest of the redisplay algorithm is about the same as
1247 windows_or_buffers_changed anyway. */
1248 if (windows_or_buffers_changed
cf074754 1249 || !NILP (w->update_mode_line)
90adcf20
RS
1250 || (XFASTINT (w->last_modified) < MODIFF
1251 && (XFASTINT (w->last_modified)
42640f83 1252 <= BUF_SAVE_MODIFF (XBUFFER (w->buffer)))))
90adcf20
RS
1253 {
1254 struct buffer *prev = current_buffer;
a2725ab2
RS
1255 int count = specpdl_ptr - specpdl;
1256
1257 if (!save_match_data)
1258 record_unwind_protect (Fstore_match_data, Fmatch_data ());
1259
cf074754 1260 call1 (Vrun_hooks, Qmenu_bar_update_hook);
90adcf20 1261 current_buffer = XBUFFER (w->buffer);
8351baf2 1262 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
90adcf20 1263 current_buffer = prev;
76412d64 1264#ifdef USE_X_TOOLKIT
01a054bc 1265 set_frame_menubar (f, 0);
76412d64 1266#endif /* USE_X_TOOLKIT */
a2725ab2
RS
1267
1268 unbind_to (count, Qnil);
90adcf20
RS
1269 }
1270 }
1271}
1272\f
a2889657
JB
1273int do_id = 1;
1274
90adcf20
RS
1275/* Redisplay WINDOW and its subwindows and siblings. */
1276
a2889657
JB
1277static void
1278redisplay_windows (window)
1279 Lisp_Object window;
1280{
265a9e55 1281 for (; !NILP (window); window = XWINDOW (window)->next)
a2889657
JB
1282 redisplay_window (window, 0);
1283}
1284
90adcf20
RS
1285/* Redisplay window WINDOW and its subwindows. */
1286
a2889657
JB
1287static void
1288redisplay_window (window, just_this_one)
1289 Lisp_Object window;
1290 int just_this_one;
1291{
1292 register struct window *w = XWINDOW (window);
30c566e4 1293 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
a2889657 1294 int height;
ae3b1442 1295 register int lpoint = PT;
a2889657 1296 struct buffer *old = current_buffer;
b1d1124b 1297 register int width = window_internal_width (w) - 1;
a2889657
JB
1298 register int startp;
1299 register int hscroll = XINT (w->hscroll);
1300 struct position pos;
ae3b1442 1301 int opoint = PT;
a2889657 1302 int tem;
e481f960 1303 int update_mode_line;
a2889657 1304
44fa5b1e 1305 if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
a2889657
JB
1306
1307 /* If this is a combination window, do its children; that's all. */
1308
265a9e55 1309 if (!NILP (w->vchild))
a2889657
JB
1310 {
1311 redisplay_windows (w->vchild);
1312 return;
1313 }
265a9e55 1314 if (!NILP (w->hchild))
a2889657
JB
1315 {
1316 redisplay_windows (w->hchild);
1317 return;
1318 }
265a9e55 1319 if (NILP (w->buffer))
a2889657 1320 abort ();
8de2d90b
JB
1321
1322 height = window_internal_height (w);
4d641a15 1323 update_mode_line = (!NILP (w->update_mode_line) || update_mode_lines);
8de2d90b
JB
1324
1325 if (MINI_WINDOW_P (w))
1326 {
1327 if (w == XWINDOW (minibuf_window))
1328 {
1329 if (echo_area_glyphs)
1330 /* We've already displayed the echo area glyphs, if any. */
88f22aff 1331 goto finish_scroll_bars;
8de2d90b
JB
1332 }
1333 else
1334 {
1335 /* This is a minibuffer, but it's not the currently active one, so
1336 clear it. */
44fa5b1e 1337 int vpos = XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top);
8de2d90b
JB
1338 int i;
1339
1340 for (i = 0; i < height; i++)
1341 {
44fa5b1e 1342 get_display_line (f, vpos + i, 0);
278feba9 1343 display_string (w, vpos + i, "", 0, 0, 0, 1, 0, width);
8de2d90b
JB
1344 }
1345
88f22aff 1346 goto finish_scroll_bars;
8de2d90b
JB
1347 }
1348 }
a2889657 1349
a2889657
JB
1350 /* Otherwise set up data on this window; select its buffer and point value */
1351
e481f960
RS
1352 if (update_mode_line)
1353 set_buffer_internal (XBUFFER (w->buffer));
1354 else
1355 set_buffer_temp (XBUFFER (w->buffer));
1356
ae3b1442 1357 opoint = PT;
a2889657 1358
42640f83
RS
1359 /* Count number of windows showing the selected buffer.
1360 An indirect buffer counts as its base buffer. */
a2889657 1361
42640f83
RS
1362 if (!just_this_one)
1363 {
1364 struct buffer *current_base, *window_base;
1365 current_base = current_buffer;
1366 window_base = XBUFFER (XWINDOW (selected_window)->buffer);
1367 if (current_base->base_buffer)
1368 current_base = current_base->base_buffer;
1369 if (window_base->base_buffer)
1370 window_base = window_base->base_buffer;
1371 if (current_base == window_base)
1372 buffer_shared++;
1373 }
a2889657
JB
1374
1375 /* POINT refers normally to the selected window.
1376 For any other window, set up appropriate value. */
1377
1378 if (!EQ (window, selected_window))
1379 {
f67a0f51
RS
1380 int new_pt = marker_position (w->pointm);
1381 if (new_pt < BEGV)
a2889657 1382 {
f67a0f51
RS
1383 new_pt = BEGV;
1384 Fset_marker (w->pointm, make_number (new_pt), Qnil);
a2889657 1385 }
f67a0f51 1386 else if (new_pt > (ZV - 1))
a2889657 1387 {
f67a0f51
RS
1388 new_pt = ZV;
1389 Fset_marker (w->pointm, make_number (new_pt), Qnil);
a2889657 1390 }
f67a0f51
RS
1391 /* We don't use SET_PT so that the point-motion hooks don't run. */
1392 BUF_PT (current_buffer) = new_pt;
a2889657
JB
1393 }
1394
f4faa47c
JB
1395 /* If any of the character widths specified in the display table
1396 have changed, invalidate the width run cache. It's true that this
1397 may be a bit late to catch such changes, but the rest of
1398 redisplay goes (non-fatally) haywire when the display table is
1399 changed, so why should we worry about doing any better? */
1400 if (current_buffer->width_run_cache)
1401 {
1402 struct Lisp_Vector *disptab = buffer_display_table ();
1403
1404 if (! disptab_matches_widthtab (disptab,
1405 XVECTOR (current_buffer->width_table)))
1406 {
1407 invalidate_region_cache (current_buffer,
1408 current_buffer->width_run_cache,
1409 BEG, Z);
1410 recompute_width_table (current_buffer, disptab);
1411 }
1412 }
1413
a2889657 1414 /* If window-start is screwed up, choose a new one. */
a2889657
JB
1415 if (XMARKER (w->start)->buffer != current_buffer)
1416 goto recenter;
1417
1418 startp = marker_position (w->start);
1419
8de2d90b 1420 /* Handle case where place to start displaying has been specified,
aa6d10fa 1421 unless the specified location is outside the accessible range. */
265a9e55 1422 if (!NILP (w->force_start))
a2889657 1423 {
aa6d10fa
RS
1424 /* Forget any recorded base line for line number display. */
1425 w->base_line_number = Qnil;
e481f960
RS
1426 /* Redisplay the mode line. Select the buffer properly for that. */
1427 if (!update_mode_line)
1428 {
1429 set_buffer_temp (old);
1430 set_buffer_internal (XBUFFER (w->buffer));
1431 update_mode_line = 1;
1432 w->update_mode_line = Qt;
1433 }
a2889657 1434 w->force_start = Qnil;
c2213350 1435 XSETFASTINT (w->last_modified, 0);
8de2d90b
JB
1436 if (startp < BEGV) startp = BEGV;
1437 if (startp > ZV) startp = ZV;
a2889657
JB
1438 try_window (window, startp);
1439 if (cursor_vpos < 0)
1440 {
1441 /* If point does not appear, move point so it does appear */
1442 pos = *compute_motion (startp, 0,
ca26e1c8
KH
1443 (((EQ (window, minibuf_window)
1444 && startp == BEG)
1445 ? minibuf_prompt_width : 0)
1446 + (hscroll ? 1 - hscroll : 0)),
1447 0,
1448 ZV, height / 2,
1449 - (1 << (SHORTBITS - 1)),
1450 width, hscroll, pos_tab_offset (w, startp), w);
f67a0f51 1451 BUF_PT (current_buffer) = pos.bufpos;
90adcf20 1452 if (w != XWINDOW (selected_window))
ae3b1442 1453 Fset_marker (w->pointm, make_number (PT), Qnil);
a2889657
JB
1454 else
1455 {
9d6a6bb9 1456 if (current_buffer == old)
ae3b1442 1457 lpoint = PT;
210e752f
KH
1458 FRAME_CURSOR_X (f) = (XFASTINT (w->left)
1459 + minmax (0, pos.hpos, width));
44fa5b1e 1460 FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
a2889657 1461 }
df0b5ea1
RS
1462 /* If we are highlighting the region,
1463 then we just changed the region, so redisplay to show it. */
df0b5ea1
RS
1464 if (!NILP (Vtransient_mark_mode)
1465 && !NILP (current_buffer->mark_active))
6f27fa9b
RS
1466 {
1467 cancel_my_columns (XWINDOW (window));
1468 try_window (window, startp);
1469 }
a2889657
JB
1470 }
1471 goto done;
1472 }
1473
1474 /* Handle case where text has not changed, only point,
44fa5b1e 1475 and it has not moved off the frame */
a2889657
JB
1476
1477 /* This code is not used for minibuffer for the sake of
1478 the case of redisplaying to replace an echo area message;
1479 since in that case the minibuffer contents per se are usually unchanged.
1480 This code is of no real use in the minibuffer since
1481 the handling of this_line_bufpos, etc.,
1482 in redisplay handles the same cases. */
1483
1484 if (XFASTINT (w->last_modified) >= MODIFF
ae3b1442 1485 && PT >= startp && !clip_changed
44fa5b1e 1486 && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
b1aa6cb3
RS
1487 /* If force-mode-line-update was called, really redisplay;
1488 that's how redisplay is forced after e.g. changing
1489 buffer-invisibility-spec. */
632ab665 1490 && NILP (w->update_mode_line)
bd66d1ba
RS
1491 /* Can't use this case if highlighting a region. */
1492 && !(!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
1493 && NILP (w->region_showing)
15495c73
KH
1494 /* If end pos is out of date, scroll bar and percentage will be wrong */
1495 && INTEGERP (w->window_end_vpos)
1496 && XFASTINT (w->window_end_vpos) < XFASTINT (w->height)
a2889657
JB
1497 && !EQ (window, minibuf_window))
1498 {
ca26e1c8 1499 pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), 0,
632ab665 1500 PT, height, 0, width, hscroll,
e37f06d7 1501 pos_tab_offset (w, startp), w);
a2889657
JB
1502
1503 if (pos.vpos < height)
1504 {
44fa5b1e
JB
1505 /* Ok, point is still on frame */
1506 if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
a2889657
JB
1507 {
1508 /* These variables are supposed to be origin 1 */
210e752f
KH
1509 FRAME_CURSOR_X (f) = (XFASTINT (w->left)
1510 + minmax (0, pos.hpos, width));
44fa5b1e 1511 FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
a2889657
JB
1512 }
1513 /* This doesn't do the trick, because if a window to the right of
1514 this one must be redisplayed, this does nothing because there
44fa5b1e 1515 is nothing in DesiredFrame yet, and then the other window is
a2889657 1516 redisplayed, making likes that are empty in this window's columns.
44fa5b1e 1517 if (XFASTINT (w->width) != FRAME_WIDTH (f))
a2889657
JB
1518 preserve_my_columns (w);
1519 */
1520 goto done;
1521 }
1522 /* Don't bother trying redisplay with same start;
1523 we already know it will lose */
1524 }
1525 /* If current starting point was originally the beginning of a line
1526 but no longer is, find a new starting point. */
265a9e55 1527 else if (!NILP (w->start_at_line_beg)
b16234d8 1528 && !(startp <= BEGV
a2889657
JB
1529 || FETCH_CHAR (startp - 1) == '\n'))
1530 {
1531 goto recenter;
1532 }
1533 else if (just_this_one && !MINI_WINDOW_P (w)
ae3b1442 1534 && PT >= startp
a2889657 1535 && XFASTINT (w->last_modified)
14709f21
JB
1536 /* or else vmotion on first line won't work. */
1537 && ! NILP (w->start_at_line_beg)
a2889657
JB
1538 && ! EQ (w->window_end_valid, Qnil)
1539 && do_id && !clip_changed
1540 && !blank_end_of_window
44fa5b1e 1541 && XFASTINT (w->width) == FRAME_WIDTH (f)
bd66d1ba
RS
1542 /* Can't use this case if highlighting a region. */
1543 && !(!NILP (Vtransient_mark_mode)
1544 && !NILP (current_buffer->mark_active))
1545 && NILP (w->region_showing)
a2889657
JB
1546 && EQ (last_arrow_position, Voverlay_arrow_position)
1547 && EQ (last_arrow_string, Voverlay_arrow_string)
44fa5b1e 1548 && (tem = try_window_id (FRAME_SELECTED_WINDOW (f)))
a2889657
JB
1549 && tem != -2)
1550 {
1551 /* tem > 0 means success. tem == -1 means choose new start.
1552 tem == -2 means try again with same start,
1553 and nothing but whitespace follows the changed stuff.
1554 tem == 0 means try again with same start. */
1555 if (tem > 0)
1556 goto done;
1557 }
1558 else if (startp >= BEGV && startp <= ZV
1559 /* Avoid starting display at end of buffer! */
8de2d90b 1560 && (startp < ZV || startp == BEGV
a2889657
JB
1561 || (XFASTINT (w->last_modified) >= MODIFF)))
1562 {
1563 /* Try to redisplay starting at same place as before */
44fa5b1e 1564 /* If point has not moved off frame, accept the results */
a2889657
JB
1565 try_window (window, startp);
1566 if (cursor_vpos >= 0)
aa6d10fa
RS
1567 {
1568 if (!just_this_one || clip_changed || beg_unchanged < startp)
1569 /* Forget any recorded base line for line number display. */
1570 w->base_line_number = Qnil;
1571 goto done;
1572 }
a2889657
JB
1573 else
1574 cancel_my_columns (w);
1575 }
1576
c2213350 1577 XSETFASTINT (w->last_modified, 0);
e481f960
RS
1578 /* Redisplay the mode line. Select the buffer properly for that. */
1579 if (!update_mode_line)
1580 {
1581 set_buffer_temp (old);
1582 set_buffer_internal (XBUFFER (w->buffer));
1583 update_mode_line = 1;
1584 w->update_mode_line = Qt;
1585 }
a2889657
JB
1586
1587 /* Try to scroll by specified few lines */
1588
1589 if (scroll_step && !clip_changed)
1590 {
ae3b1442 1591 if (PT > startp)
a2889657 1592 {
210e752f 1593 pos = *vmotion (Z - XFASTINT (w->window_end_pos), scroll_step, w);
a2889657
JB
1594 if (pos.vpos >= height)
1595 goto scroll_fail;
1596 }
1597
210e752f 1598 pos = *vmotion (startp, (PT < startp ? - scroll_step : scroll_step), w);
a2889657 1599
ae3b1442 1600 if (PT >= pos.bufpos)
a2889657
JB
1601 {
1602 try_window (window, pos.bufpos);
1603 if (cursor_vpos >= 0)
aa6d10fa
RS
1604 {
1605 if (!just_this_one || clip_changed || beg_unchanged < startp)
1606 /* Forget any recorded base line for line number display. */
1607 w->base_line_number = Qnil;
1608 goto done;
1609 }
a2889657
JB
1610 else
1611 cancel_my_columns (w);
1612 }
1613 scroll_fail: ;
1614 }
1615
1616 /* Finally, just choose place to start which centers point */
1617
1618recenter:
aa6d10fa
RS
1619 /* Forget any previously recorded base line for line number display. */
1620 w->base_line_number = Qnil;
1621
210e752f 1622 pos = *vmotion (PT, - (height / 2), w);
a2889657
JB
1623 try_window (window, pos.bufpos);
1624
1625 startp = marker_position (w->start);
ca26e1c8 1626 w->start_at_line_beg
b16234d8 1627 = (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
a2889657
JB
1628
1629done:
e481f960 1630 if ((update_mode_line
aa6d10fa
RS
1631 /* If window not full width, must redo its mode line
1632 if the window to its side is being redone */
1633 || (!just_this_one && width < FRAME_WIDTH (f) - 1)
155ef550
KH
1634 || INTEGERP (w->base_line_pos)
1635 || (!NILP (w->column_number_displayed)
1636 && XFASTINT (w->column_number_displayed) != current_column ()))
a2889657
JB
1637 && height != XFASTINT (w->height))
1638 display_mode_line (w);
aa6d10fa
RS
1639 if (! line_number_displayed
1640 && ! BUFFERP (w->base_line_pos))
1641 {
1642 w->base_line_pos = Qnil;
1643 w->base_line_number = Qnil;
1644 }
a2889657 1645
7ce2c095 1646 /* When we reach a frame's selected window, redo the frame's menu bar. */
e481f960 1647 if (update_mode_line
76412d64
RS
1648#ifdef USE_X_TOOLKIT
1649 && FRAME_EXTERNAL_MENU_BAR (f)
1650#else
7ce2c095 1651 && FRAME_MENU_BAR_LINES (f) > 0
76412d64 1652#endif
7ce2c095
RS
1653 && EQ (FRAME_SELECTED_WINDOW (f), window))
1654 display_menu_bar (w);
1655
88f22aff
JB
1656 finish_scroll_bars:
1657 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
30c566e4 1658 {
b1d1124b 1659 int start, end, whole;
30c566e4 1660
b1d1124b 1661 /* Calculate the start and end positions for the current window.
3505ea70
JB
1662 At some point, it would be nice to choose between scrollbars
1663 which reflect the whole buffer size, with special markers
1664 indicating narrowing, and scrollbars which reflect only the
1665 visible region.
1666
b1d1124b
JB
1667 Note that minibuffers sometimes aren't displaying any text. */
1668 if (! MINI_WINDOW_P (w)
1669 || (w == XWINDOW (minibuf_window) && ! echo_area_glyphs))
1670 {
8a9311d7 1671 whole = ZV - BEGV;
4d641a15 1672 start = marker_position (w->start) - BEGV;
b1d1124b
JB
1673 /* I don't think this is guaranteed to be right. For the
1674 moment, we'll pretend it is. */
85f26be9 1675 end = (Z - XINT (w->window_end_pos)) - BEGV;
3505ea70
JB
1676
1677 if (end < start) end = start;
8a9311d7 1678 if (whole < (end - start)) whole = end - start;
b1d1124b
JB
1679 }
1680 else
1681 start = end = whole = 0;
30c566e4 1682
88f22aff 1683 /* Indicate what this scroll bar ought to be displaying now. */
7eb9ba41 1684 (*set_vertical_scroll_bar_hook) (w, end - start, whole, start);
30c566e4 1685
88f22aff 1686 /* Note that we actually used the scroll bar attached to this window,
30c566e4 1687 so it shouldn't be deleted at the end of redisplay. */
88f22aff 1688 (*redeem_scroll_bar_hook) (w);
30c566e4 1689 }
b1d1124b 1690
f67a0f51 1691 BUF_PT (current_buffer) = opoint;
e481f960
RS
1692 if (update_mode_line)
1693 set_buffer_internal (old);
1694 else
1695 set_buffer_temp (old);
f67a0f51 1696 BUF_PT (current_buffer) = lpoint;
a2889657
JB
1697}
1698\f
1699/* Do full redisplay on one window, starting at position `pos'. */
1700
1701static void
1702try_window (window, pos)
1703 Lisp_Object window;
1704 register int pos;
1705{
1706 register struct window *w = XWINDOW (window);
1707 register int height = window_internal_height (w);
1708 register int vpos = XFASTINT (w->top);
1709 register int last_text_vpos = vpos;
1710 int tab_offset = pos_tab_offset (w, pos);
44fa5b1e 1711 FRAME_PTR f = XFRAME (w->frame);
b1d1124b 1712 int width = window_internal_width (w) - 1;
a2889657
JB
1713 struct position val;
1714
1715 Fset_marker (w->start, make_number (pos), Qnil);
1716 cursor_vpos = -1;
1717 overlay_arrow_seen = 0;
ca26e1c8 1718 zv_strings_seen = 0;
a2889657
JB
1719 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
1720
1721 while (--height >= 0)
1722 {
1723 val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
1724 tab_offset += width;
2b050fec
RS
1725 /* For the first line displayed, display_text_line
1726 subtracts the prompt width from the tab offset.
1727 But it does not affect the value of our variable tab_offset.
1728 So we do the subtraction again,
1729 for the sake of continuation lines of that first line. */
1730 if (MINI_WINDOW_P (w) && vpos == XFASTINT (w->top))
1731 tab_offset -= minibuf_prompt_width;
1732
a2889657
JB
1733 if (val.vpos) tab_offset = 0;
1734 vpos++;
1735 if (pos != val.bufpos)
642eefc6
RS
1736 {
1737 int invis = 0;
e885523c 1738#ifdef USE_TEXT_PROPERTIES
642eefc6
RS
1739 Lisp_Object invis_prop;
1740 invis_prop = Fget_char_property (val.bufpos-1, Qinvisible, window);
1741 invis = TEXT_PROP_MEANS_INVISIBLE (invis_prop);
e885523c 1742#endif
642eefc6
RS
1743
1744 last_text_vpos
1745 /* Next line, unless prev line ended in end of buffer with no cr */
1746 = vpos - (val.vpos
1747 && (FETCH_CHAR (val.bufpos - 1) != '\n' || invis));
1748 }
a2889657
JB
1749 pos = val.bufpos;
1750 }
1751
1752 /* If last line is continued in middle of character,
44fa5b1e 1753 include the split character in the text considered on the frame */
a2889657
JB
1754 if (val.hpos < (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
1755 pos++;
1756
44fa5b1e 1757 /* If bottom just moved off end of frame, change mode line percentage. */
a2889657
JB
1758 if (XFASTINT (w->window_end_pos) == 0
1759 && Z != pos)
1760 w->update_mode_line = Qt;
1761
44fa5b1e 1762 /* Say where last char on frame will be, once redisplay is finished. */
c2213350
KH
1763 XSETFASTINT (w->window_end_pos, Z - pos);
1764 XSETFASTINT (w->window_end_vpos, last_text_vpos - XFASTINT (w->top));
a2889657
JB
1765 /* But that is not valid info until redisplay finishes. */
1766 w->window_end_valid = Qnil;
1767}
1768\f
1769/* Try to redisplay when buffer is modified locally,
1770 computing insert/delete line to preserve text outside
1771 the bounds of the changes.
1772 Return 1 if successful, 0 if if cannot tell what to do,
1773 or -1 to tell caller to find a new window start,
1774 or -2 to tell caller to do normal redisplay with same window start. */
1775
1776static int
1777try_window_id (window)
1778 Lisp_Object window;
1779{
1780 int pos;
1781 register struct window *w = XWINDOW (window);
1782 register int height = window_internal_height (w);
44fa5b1e 1783 FRAME_PTR f = XFRAME (w->frame);
a2889657
JB
1784 int top = XFASTINT (w->top);
1785 int start = marker_position (w->start);
b1d1124b 1786 int width = window_internal_width (w) - 1;
a2889657
JB
1787 int hscroll = XINT (w->hscroll);
1788 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
ca26e1c8 1789 int did_motion;
a2889657
JB
1790 register int vpos;
1791 register int i, tem;
1792 int last_text_vpos = 0;
1793 int stop_vpos;
e24c997d
KH
1794 int selective = (INTEGERP (current_buffer->selective_display)
1795 ? XINT (current_buffer->selective_display)
1796 : !NILP (current_buffer->selective_display) ? -1 : 0);
a2889657
JB
1797
1798 struct position val, bp, ep, xp, pp;
1799 int scroll_amount = 0;
1800 int delta;
1801 int tab_offset, epto;
1802
1803 if (GPT - BEG < beg_unchanged)
1804 beg_unchanged = GPT - BEG;
1805 if (Z - GPT < end_unchanged)
1806 end_unchanged = Z - GPT;
1807
6a1dc7ac 1808 if (beg_unchanged + BEG < start)
a2889657
JB
1809 return 0; /* Give up if changes go above top of window */
1810
1811 /* Find position before which nothing is changed. */
ca26e1c8 1812 bp = *compute_motion (start, 0, lmargin, 0,
632ab665 1813 min (ZV, beg_unchanged + BEG), height, 0,
e37f06d7 1814 width, hscroll, pos_tab_offset (w, start), w);
a2889657 1815 if (bp.vpos >= height)
6e8290aa 1816 {
632ab665 1817 if (PT < bp.bufpos)
6e8290aa 1818 {
44fa5b1e
JB
1819 /* All changes are below the frame, and point is on the frame.
1820 We don't need to change the frame at all.
6e8290aa
JB
1821 But we need to update window_end_pos to account for
1822 any change in buffer size. */
ca26e1c8 1823 bp = *compute_motion (start, 0, lmargin, 0,
f7be7f78 1824 Z, height, 0,
e37f06d7 1825 width, hscroll, pos_tab_offset (w, start), w);
c2213350
KH
1826 XSETFASTINT (w->window_end_vpos, height);
1827 XSETFASTINT (w->window_end_pos, Z - bp.bufpos);
4d641a15 1828 goto findpoint;
6e8290aa
JB
1829 }
1830 return 0;
1831 }
a2889657
JB
1832
1833 vpos = bp.vpos;
1834
44fa5b1e 1835 /* Find beginning of that frame line. Must display from there. */
210e752f 1836 bp = *vmotion (bp.bufpos, 0, w);
a2889657
JB
1837
1838 pos = bp.bufpos;
1839 val.hpos = lmargin;
1840 if (pos < start)
1841 return -1;
1842
ca26e1c8 1843 did_motion = 0;
a2889657 1844 /* If about to start displaying at the beginning of a continuation line,
44fa5b1e 1845 really start with previous frame line, in case it was not
a2889657 1846 continued when last redisplayed */
05ba02eb
JB
1847 if ((bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0)
1848 ||
1849 /* Likewise if we have to worry about selective display. */
9f412332 1850 (selective > 0 && bp.bufpos - 1 == beg_unchanged && vpos > 0))
a2889657 1851 {
210e752f 1852 bp = *vmotion (bp.bufpos, -1, w);
a2889657
JB
1853 --vpos;
1854 pos = bp.bufpos;
1855 }
1856
1857 if (bp.contin && bp.hpos != lmargin)
1858 {
1859 val.hpos = bp.prevhpos - width + lmargin;
ca26e1c8 1860 did_motion = 1;
a2889657
JB
1861 pos--;
1862 }
1863
1864 bp.vpos = vpos;
1865
1866 /* Find first visible newline after which no more is changed. */
1867 tem = find_next_newline (Z - max (end_unchanged, Z - ZV), 1);
9f412332
KH
1868 if (selective > 0)
1869 while (tem < ZV - 1 && (indented_beyond_p (tem, selective)))
a2889657
JB
1870 tem = find_next_newline (tem, 1);
1871
1872 /* Compute the cursor position after that newline. */
ca26e1c8 1873 ep = *compute_motion (pos, vpos, val.hpos, did_motion, tem,
a2889657 1874 height, - (1 << (SHORTBITS - 1)),
e37f06d7 1875 width, hscroll, pos_tab_offset (w, bp.bufpos), w);
a2889657 1876
44fa5b1e
JB
1877 /* If changes reach past the text available on the frame,
1878 just display rest of frame. */
a2889657
JB
1879 if (ep.bufpos > Z - XFASTINT (w->window_end_pos))
1880 stop_vpos = height;
1881 else
1882 stop_vpos = ep.vpos;
1883
1884 /* If no newline before ep, the line ep is on includes some changes
1885 that must be displayed. Make sure we don't stop before it. */
1886 /* Also, if changes reach all the way until ep.bufpos,
1887 it is possible that something was deleted after the
1888 newline before it, so the following line must be redrawn. */
1889 if (stop_vpos == ep.vpos
1890 && (ep.bufpos == BEGV
1891 || FETCH_CHAR (ep.bufpos - 1) != '\n'
1892 || ep.bufpos == Z - end_unchanged))
1893 stop_vpos = ep.vpos + 1;
1894
1895 cursor_vpos = -1;
1896 overlay_arrow_seen = 0;
ca26e1c8 1897 zv_strings_seen = 0;
a2889657
JB
1898
1899 /* If changes do not reach to bottom of window,
1900 figure out how much to scroll the rest of the window */
1901 if (stop_vpos < height)
1902 {
1903 /* Now determine how far up or down the rest of the window has moved */
1904 epto = pos_tab_offset (w, ep.bufpos);
ca26e1c8 1905 xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
a2889657 1906 Z - XFASTINT (w->window_end_pos),
e37f06d7 1907 10000, 0, width, hscroll, epto, w);
a2889657
JB
1908 scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
1909
44fa5b1e 1910 /* Is everything on frame below the changes whitespace?
a2889657
JB
1911 If so, no scrolling is really necessary. */
1912 for (i = ep.bufpos; i < xp.bufpos; i++)
1913 {
1914 tem = FETCH_CHAR (i);
1915 if (tem != ' ' && tem != '\n' && tem != '\t')
1916 break;
1917 }
1918 if (i == xp.bufpos)
1919 return -2;
1920
e8e536a9
KH
1921 XSETFASTINT (w->window_end_vpos,
1922 XFASTINT (w->window_end_vpos) + scroll_amount);
a2889657 1923
44fa5b1e 1924 /* Before doing any scrolling, verify that point will be on frame. */
ae3b1442 1925 if (PT > ep.bufpos && !(PT <= xp.bufpos && xp.bufpos < height))
a2889657 1926 {
ae3b1442 1927 if (PT <= xp.bufpos)
a2889657 1928 {
ca26e1c8 1929 pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
ae3b1442 1930 PT, height, - (1 << (SHORTBITS - 1)),
e37f06d7 1931 width, hscroll, epto, w);
a2889657
JB
1932 }
1933 else
1934 {
ca26e1c8 1935 pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos, 1,
ae3b1442 1936 PT, height, - (1 << (SHORTBITS - 1)),
e37f06d7
KH
1937 width, hscroll,
1938 pos_tab_offset (w, xp.bufpos), w);
a2889657 1939 }
ae3b1442 1940 if (pp.bufpos < PT || pp.vpos == height)
a2889657
JB
1941 return 0;
1942 cursor_vpos = pp.vpos + top;
210e752f 1943 cursor_hpos = XFASTINT (w->left) + minmax (0, pp.hpos, width);
a2889657
JB
1944 }
1945
1946 if (stop_vpos - scroll_amount >= height
1947 || ep.bufpos == xp.bufpos)
1948 {
1949 if (scroll_amount < 0)
1950 stop_vpos -= scroll_amount;
1951 scroll_amount = 0;
1952 /* In this path, we have altered window_end_vpos
1953 and not left it negative.
1954 We must make sure that, in case display is preempted
44fa5b1e 1955 before the frame changes to reflect what we do here,
a2889657 1956 further updates will not come to try_window_id
44fa5b1e 1957 and assume the frame and window_end_vpos match. */
a2889657
JB
1958 blank_end_of_window = 1;
1959 }
1960 else if (!scroll_amount)
0d231165
RS
1961 {
1962 /* Even if we don't need to scroll, we must adjust the
1963 charstarts of subsequent lines (that we won't redisplay)
1964 according to the amount of text inserted or deleted. */
1965 int oldpos = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0];
1966 int adjust = ep.bufpos - oldpos;
1967 adjust_window_charstarts (w, ep.vpos + top - 1, adjust);
1968 }
a2889657
JB
1969 else if (bp.bufpos == Z - end_unchanged)
1970 {
1971 /* If reprinting everything is nearly as fast as scrolling,
1972 don't bother scrolling. Can happen if lines are short. */
44fa5b1e 1973 if (scroll_cost (f, bp.vpos + top - scroll_amount,
a2889657
JB
1974 top + height - max (0, scroll_amount),
1975 scroll_amount)
1976 > xp.bufpos - bp.bufpos - 20)
1977 /* Return "try normal display with same window-start."
1978 Too bad we can't prevent further scroll-thinking. */
1979 return -2;
1980 /* If pure deletion, scroll up as many lines as possible.
1981 In common case of killing a line, this can save the
1982 following line from being overwritten by scrolling
1983 and therefore having to be redrawn. */
44fa5b1e 1984 tem = scroll_frame_lines (f, bp.vpos + top - scroll_amount,
d1cb44a4
RS
1985 top + height - max (0, scroll_amount),
1986 scroll_amount, bp.bufpos);
d2f84654
RS
1987 if (!tem)
1988 stop_vpos = height;
1989 else
1990 {
1991 /* scroll_frame_lines did not properly adjust subsequent
1992 lines' charstarts in the case where the text of the
1993 screen line at bp.vpos has changed.
1994 (This can happen in a deletion that ends in mid-line.)
1995 To adjust properly, we need to make things constent at
1996 the position ep.
1997 So do a second adjust to make that happen.
1998 Note that stop_vpos >= ep.vpos, so it is sufficient
1999 to update the charstarts for lines at ep.vpos and below. */
2000 int oldstart
2001 = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0];
2002 adjust_window_charstarts (w, ep.vpos + top - 1,
2003 ep.bufpos - oldstart);
2004 }
a2889657
JB
2005 }
2006 else if (scroll_amount)
2007 {
2008 /* If reprinting everything is nearly as fast as scrolling,
2009 don't bother scrolling. Can happen if lines are short. */
2010 /* Note that if scroll_amount > 0, xp.bufpos - bp.bufpos is an
2011 overestimate of cost of reprinting, since xp.bufpos
2012 would end up below the bottom of the window. */
44fa5b1e 2013 if (scroll_cost (f, ep.vpos + top - scroll_amount,
a2889657
JB
2014 top + height - max (0, scroll_amount),
2015 scroll_amount)
2016 > xp.bufpos - ep.bufpos - 20)
2017 /* Return "try normal display with same window-start."
2018 Too bad we can't prevent further scroll-thinking. */
2019 return -2;
44fa5b1e 2020 tem = scroll_frame_lines (f, ep.vpos + top - scroll_amount,
a2889657 2021 top + height - max (0, scroll_amount),
d1cb44a4 2022 scroll_amount, ep.bufpos);
a2889657
JB
2023 if (!tem) stop_vpos = height;
2024 }
2025 }
2026
2027 /* In any case, do not display past bottom of window */
2028 if (stop_vpos >= height)
2029 {
2030 stop_vpos = height;
2031 scroll_amount = 0;
2032 }
2033
2034 /* Handle case where pos is before w->start --
2035 can happen if part of line had been clipped and is not clipped now */
2036 if (vpos == 0 && pos < marker_position (w->start))
2037 Fset_marker (w->start, make_number (pos), Qnil);
2038
2039 /* Redisplay the lines where the text was changed */
2040 last_text_vpos = vpos;
2041 tab_offset = pos_tab_offset (w, pos);
2042 /* If we are starting display in mid-character, correct tab_offset
2043 to account for passing the line that that character really starts in. */
2044 if (val.hpos < lmargin)
2045 tab_offset += width;
2046 while (vpos < stop_vpos)
2047 {
2048 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
2049 tab_offset += width;
2050 if (val.vpos) tab_offset = 0;
2051 if (pos != val.bufpos)
2052 last_text_vpos
2053 /* Next line, unless prev line ended in end of buffer with no cr */
2054 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
2055 pos = val.bufpos;
2056 }
2057
2058 /* There are two cases:
2059 1) we have displayed down to the bottom of the window
2060 2) we have scrolled lines below stop_vpos by scroll_amount */
2061
2062 if (vpos == height)
2063 {
2064 /* If last line is continued in middle of character,
44fa5b1e 2065 include the split character in the text considered on the frame */
a2889657
JB
2066 if (val.hpos < lmargin)
2067 val.bufpos++;
c2213350
KH
2068 XSETFASTINT (w->window_end_vpos, last_text_vpos);
2069 XSETFASTINT (w->window_end_pos, Z - val.bufpos);
a2889657
JB
2070 }
2071
2072 /* If scrolling made blank lines at window bottom,
2073 redisplay to fill those lines */
2074 if (scroll_amount < 0)
2075 {
2076 /* Don't consider these lines for general-purpose scrolling.
2077 That will save time in the scrolling computation. */
44fa5b1e 2078 FRAME_SCROLL_BOTTOM_VPOS (f) = xp.vpos;
a2889657
JB
2079 vpos = xp.vpos;
2080 pos = xp.bufpos;
2081 val.hpos = lmargin;
2082 if (pos == ZV)
2083 vpos = height + scroll_amount;
2084 else if (xp.contin && xp.hpos != lmargin)
2085 {
2086 val.hpos = xp.prevhpos - width + lmargin;
2087 pos--;
2088 }
2089
2090 blank_end_of_window = 1;
2091 tab_offset = pos_tab_offset (w, pos);
2092 /* If we are starting display in mid-character, correct tab_offset
2093 to account for passing the line that that character starts in. */
2094 if (val.hpos < lmargin)
2095 tab_offset += width;
2096
2097 while (vpos < height)
2098 {
2099 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
2100 tab_offset += width;
2101 if (val.vpos) tab_offset = 0;
2102 pos = val.bufpos;
2103 }
2104
2105 /* Here is a case where display_text_line sets cursor_vpos wrong.
2106 Make it be fixed up, below. */
2107 if (xp.bufpos == ZV
ae3b1442 2108 && xp.bufpos == PT)
a2889657
JB
2109 cursor_vpos = -1;
2110 }
2111
44fa5b1e 2112 /* If bottom just moved off end of frame, change mode line percentage. */
a2889657
JB
2113 if (XFASTINT (w->window_end_pos) == 0
2114 && Z != val.bufpos)
2115 w->update_mode_line = Qt;
2116
2117 /* Attempt to adjust end-of-text positions to new bottom line */
2118 if (scroll_amount)
2119 {
2120 delta = height - xp.vpos;
2121 if (delta < 0
2122 || (delta > 0 && xp.bufpos <= ZV)
2123 || (delta == 0 && xp.hpos))
2124 {
210e752f 2125 val = *vmotion (Z - XFASTINT (w->window_end_pos), delta, w);
c2213350 2126 XSETFASTINT (w->window_end_pos, Z - val.bufpos);
e8e536a9
KH
2127 XSETFASTINT (w->window_end_vpos,
2128 XFASTINT (w->window_end_vpos) + val.vpos);
a2889657
JB
2129 }
2130 }
2131
2132 w->window_end_valid = Qnil;
2133
2134 /* If point was not in a line that was displayed, find it */
2135 if (cursor_vpos < 0)
2136 {
4d641a15 2137 findpoint:
ca26e1c8 2138 val = *compute_motion (start, 0, lmargin, 0, PT, 10000, 10000,
e37f06d7 2139 width, hscroll, pos_tab_offset (w, start), w);
44fa5b1e 2140 /* Admit failure if point is off frame now */
a2889657
JB
2141 if (val.vpos >= height)
2142 {
2143 for (vpos = 0; vpos < height; vpos++)
44fa5b1e 2144 cancel_line (vpos + top, f);
a2889657
JB
2145 return 0;
2146 }
2147 cursor_vpos = val.vpos + top;
210e752f 2148 cursor_hpos = XFASTINT (w->left) + minmax (0, val.hpos, width);
a2889657
JB
2149 }
2150
210e752f 2151 FRAME_CURSOR_X (f) = cursor_hpos;
44fa5b1e 2152 FRAME_CURSOR_Y (f) = cursor_vpos;
a2889657
JB
2153
2154 if (debug_end_pos)
2155 {
ca26e1c8 2156 val = *compute_motion (start, 0, lmargin, 0, ZV,
a2889657 2157 height, - (1 << (SHORTBITS - 1)),
e37f06d7 2158 width, hscroll, pos_tab_offset (w, start), w);
a2889657
JB
2159 if (val.vpos != XFASTINT (w->window_end_vpos))
2160 abort ();
2161 if (XFASTINT (w->window_end_pos)
2162 != Z - val.bufpos)
2163 abort ();
2164 }
2165
2166 return 1;
2167}
2168\f
31b24551
JB
2169/* Mark a section of BUF as modified, but only for the sake of redisplay.
2170 This is useful for recording changes to overlays.
2171
2172 We increment the buffer's modification timestamp and set the
2173 redisplay caches (windows_or_buffers_changed, beg_unchanged, etc)
2174 as if the region of text between START and END had been modified;
2175 the redisplay code will check this against the windows' timestamps,
2176 and redraw the appropriate area of the buffer.
2177
2178 However, if the buffer is unmodified, we bump the last-save
2179 timestamp as well, so that incrementing the timestamp doesn't fool
2180 Emacs into thinking that the buffer's text has been modified.
2181
2182 Tweaking the timestamps shouldn't hurt the first-modification
2183 timestamps recorded in the undo records; those values aren't
2184 written until just before a real text modification is made, so they
2185 will never catch the timestamp value just before this function gets
2186 called. */
2187
2188void
2189redisplay_region (buf, start, end)
2190 struct buffer *buf;
2191 int start, end;
2192{
2193 if (start == end)
2194 return;
2195
2196 if (start > end)
2197 {
2198 int temp = start;
2199 start = end; end = temp;
2200 }
2201
70bcb498
RS
2202 /* If this is a buffer not in the selected window,
2203 we must do other windows. */
2204 if (buf != XBUFFER (XWINDOW (selected_window)->buffer))
2205 windows_or_buffers_changed = 1;
99b9e975
RS
2206 /* If it's not current, we can't use beg_unchanged, end_unchanged for it. */
2207 else if (buf != current_buffer)
2208 windows_or_buffers_changed = 1;
70bcb498
RS
2209 /* If multiple windows show this buffer, we must do other windows. */
2210 else if (buffer_shared > 1)
31b24551
JB
2211 windows_or_buffers_changed = 1;
2212 else
2213 {
2214 if (unchanged_modified == MODIFF)
2215 {
2216 beg_unchanged = start - BEG;
2217 end_unchanged = Z - end;
2218 }
2219 else
2220 {
2221 if (Z - end < end_unchanged)
2222 end_unchanged = Z - end;
2223 if (start - BEG < beg_unchanged)
2224 beg_unchanged = start - BEG;
2225 }
2226 }
2227
2228 /* Increment the buffer's time stamp, but also increment the save
42640f83
RS
2229 and autosave timestamps, so as not to screw up that timekeeping. */
2230 if (BUF_MODIFF (buf) == BUF_SAVE_MODIFF (buf))
2231 BUF_SAVE_MODIFF (buf)++;
31b24551
JB
2232 if (BUF_MODIFF (buf) == buf->auto_save_modified)
2233 buf->auto_save_modified++;
2234
2235 BUF_MODIFF (buf) ++;
2236}
2237
2238\f
278feba9 2239/* Copy LEN glyphs starting address FROM to the rope TO.
f7430cb6 2240 But don't actually copy the parts that would come in before S.
278feba9
RS
2241 Value is TO, advanced past the copied data.
2242 F is the frame we are displaying in. */
a2889657 2243
278feba9
RS
2244static GLYPH *
2245copy_part_of_rope (f, to, s, from, len, face)
2246 FRAME_PTR f;
2247 register GLYPH *to; /* Copy to here. */
a2889657 2248 register GLYPH *s; /* Starting point. */
278feba9
RS
2249 Lisp_Object *from; /* Data to copy. */
2250 int len;
1c2250c2 2251 int face; /* Face to apply to glyphs which don't specify one. */
a2889657 2252{
278feba9
RS
2253 int n = len;
2254 register Lisp_Object *fp = from;
2255 /* These cache the results of the last call to compute_glyph_face. */
2256 int last_code = -1;
2257 int last_merged = 0;
c581d710 2258
87485d6f 2259#ifdef HAVE_FACES
4cdc65eb
KH
2260 if (! FRAME_TERMCAP_P (f))
2261 while (n--)
2262 {
dedd1182 2263 int glyph = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
4cdc65eb
KH
2264 int facecode;
2265
2266 if (FAST_GLYPH_FACE (glyph) == 0)
2267 /* If GLYPH has no face code, use FACE. */
2268 facecode = face;
2269 else if (FAST_GLYPH_FACE (glyph) == last_code)
2270 /* If it's same as previous glyph, use same result. */
2271 facecode = last_merged;
2272 else
2273 {
2274 /* Merge this glyph's face and remember the result. */
2275 last_code = FAST_GLYPH_FACE (glyph);
2276 last_merged = facecode = compute_glyph_face (f, last_code, face);
2277 }
b2a76982 2278
4cdc65eb
KH
2279 if (to >= s)
2280 *to = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), facecode);
2281 ++to;
2282 ++fp;
2283 }
2284 else
2285#endif
2286 while (n--)
2287 {
dedd1182 2288 if (to >= s) *to = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
4cdc65eb
KH
2289 ++to;
2290 ++fp;
2291 }
278feba9 2292 return to;
c581d710
RS
2293}
2294
278feba9
RS
2295/* Correct a glyph by replacing its specified user-level face code
2296 with a displayable computed face code. */
c581d710 2297
278feba9 2298static GLYPH
659a218f 2299fix_glyph (f, glyph, cface)
278feba9
RS
2300 FRAME_PTR f;
2301 GLYPH glyph;
659a218f 2302 int cface;
c581d710 2303{
87485d6f 2304#ifdef HAVE_FACES
659a218f
KH
2305 if (! FRAME_TERMCAP_P (f))
2306 {
2307 if (FAST_GLYPH_FACE (glyph) != 0)
2308 cface = compute_glyph_face (f, FAST_GLYPH_FACE (glyph), cface);
2309 glyph = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), cface);
2310 }
4cdc65eb
KH
2311#endif
2312 return glyph;
a2889657
JB
2313}
2314\f
f4faa47c
JB
2315/* Display one line of window W, starting at position START in W's buffer.
2316
2317 Display starting at horizontal position HPOS, expressed relative to
2318 W's left edge. In situations where the text at START shouldn't
2319 start at the left margin (i.e. when the window is hscrolled, or
2320 we're continuing a line which left off in the midst of a
2321 multi-column character), HPOS should be negative; we throw away
2322 characters up 'til hpos = 0. So, HPOS must take hscrolling into
2323 account.
a2889657
JB
2324
2325 TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
2326
f4faa47c
JB
2327 Display on position VPOS on the frame. It is origin 0, relative to
2328 the top of the frame, not W.
a2889657
JB
2329
2330 Returns a STRUCT POSITION giving character to start next line with
2331 and where to display it, including a zero or negative hpos.
2332 The vpos field is not really a vpos; it is 1 unless the line is continued */
2333
2334struct position val_display_text_line;
2335
2336static struct position *
2337display_text_line (w, start, vpos, hpos, taboffset)
2338 struct window *w;
2339 int start;
2340 int vpos;
2341 int hpos;
2342 int taboffset;
2343{
2344 register int pos = start;
2345 register int c;
2346 register GLYPH *p1;
a2889657
JB
2347 register int pause;
2348 register unsigned char *p;
2349 GLYPH *endp;
d2f84654 2350 register GLYPH *leftmargin;
ca26e1c8 2351 register GLYPH *p1prev;
efc63ef0 2352 register GLYPH *p1start;
ca26e1c8 2353 int prevpos;
efc63ef0 2354 int *charstart;
44fa5b1e 2355 FRAME_PTR f = XFRAME (w->frame);
a2889657 2356 int tab_width = XINT (current_buffer->tab_width);
265a9e55 2357 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
b1d1124b 2358 int width = window_internal_width (w) - 1;
a2889657
JB
2359 struct position val;
2360 int lastpos;
2361 int invis;
642eefc6
RS
2362 int last_invis_skip = 0;
2363 Lisp_Object last_invis_prop;
a2889657 2364 int hscroll = XINT (w->hscroll);
d2f84654
RS
2365 int truncate = (hscroll
2366 || (truncate_partial_width_windows
2367 && XFASTINT (w->width) < FRAME_WIDTH (f))
2368 || !NILP (current_buffer->truncate_lines));
bd66d1ba
RS
2369
2370 /* 1 if we should highlight the region. */
2371 int highlight_region
2372 = !NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active);
2373 int region_beg, region_end;
2374
e24c997d
KH
2375 int selective = (INTEGERP (current_buffer->selective_display)
2376 ? XINT (current_buffer->selective_display)
2377 : !NILP (current_buffer->selective_display) ? -1 : 0);
44fa5b1e 2378 register struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
a2889657 2379 register struct Lisp_Vector *dp = window_display_table (w);
68a37fa8
RS
2380
2381 Lisp_Object default_invis_vector[3];
642eefc6
RS
2382 /* Number of characters of ellipsis to display after an invisible line
2383 if it calls for an ellipsis.
2384 Note that this value can be nonzero regardless of whether
2385 selective display is enabled--you must check that separately. */
a2889657 2386 int selective_rlen
642eefc6 2387 = (dp && VECTORP (DISP_INVIS_VECTOR (dp))
68a37fa8 2388 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size
642eefc6 2389 : !NILP (current_buffer->selective_display_ellipses) ? 3 : 0);
68a37fa8
RS
2390 /* This is the sequence of Lisp objects to display
2391 when there are invisible lines. */
2392 Lisp_Object *invis_vector_contents
e24c997d 2393 = (dp && VECTORP (DISP_INVIS_VECTOR (dp))
68a37fa8
RS
2394 ? XVECTOR (DISP_INVIS_VECTOR (dp))->contents
2395 : default_invis_vector);
2396
e24c997d 2397 GLYPH truncator = (dp == 0 || !INTEGERP (DISP_TRUNC_GLYPH (dp))
278feba9 2398 ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
e24c997d 2399 GLYPH continuer = (dp == 0 || !INTEGERP (DISP_CONTINUE_GLYPH (dp))
278feba9 2400 ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
a2889657 2401
31b24551
JB
2402 /* The next buffer location at which the face should change, due
2403 to overlays or text property changes. */
2404 int next_face_change;
2405
ca26e1c8
KH
2406 /* The next location where the `invisible' property changes, or an
2407 overlay starts or ends. */
2408 int next_boundary;
2409
31b24551 2410 /* The face we're currently using. */
1c2250c2 2411 int current_face = 0;
efc63ef0 2412 int i;
31b24551 2413
c2213350 2414 XSETFASTINT (default_invis_vector[2], '.');
68a37fa8
RS
2415 default_invis_vector[0] = default_invis_vector[1] = default_invis_vector[2];
2416
a2889657 2417 hpos += XFASTINT (w->left);
44fa5b1e 2418 get_display_line (f, vpos, XFASTINT (w->left));
54ff581a 2419 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
a2889657 2420
bd66d1ba 2421 /* Show where to highlight the region. */
1613b757 2422 if (highlight_region && XMARKER (current_buffer->mark)->buffer != 0
fba9ce76
RS
2423 /* Maybe highlight only in selected window. */
2424 && (highlight_nonselected_windows
6f139a45 2425 || w == XWINDOW (selected_window)))
bd66d1ba
RS
2426 {
2427 region_beg = marker_position (current_buffer->mark);
2428 if (PT < region_beg)
2429 {
2430 region_end = region_beg;
2431 region_beg = PT;
2432 }
2433 else
2434 region_end = PT;
2435 w->region_showing = Qt;
2436 }
2437 else
2438 region_beg = region_end = -1;
2439
f4faa47c 2440 if (MINI_WINDOW_P (w)
ca26e1c8 2441 && start == BEG
a2889657
JB
2442 && vpos == XFASTINT (w->top))
2443 {
8c5b6a0a 2444 if (! NILP (minibuf_prompt))
f7b4b63a
KH
2445 {
2446 minibuf_prompt_width
8c5b6a0a
KH
2447 = (display_string (w, vpos, XSTRING (minibuf_prompt)->data,
2448 XSTRING (minibuf_prompt)->size, hpos,
ce006f69
RS
2449 /* Display a space if we truncate. */
2450 ' ',
2451 1, -1,
2452 /* Truncate the prompt a little before the
2453 margin, so user input can at least start
2454 on the first line. */
2455 w->width > 10 ? w->width - 4 : -1)
f7b4b63a
KH
2456 - hpos);
2457 hpos += minibuf_prompt_width;
2b050fec 2458 taboffset -= minibuf_prompt_width;
f7b4b63a
KH
2459 }
2460 else
2461 minibuf_prompt_width = 0;
a2889657
JB
2462 }
2463
f4faa47c
JB
2464 /* If we're hscrolled at all, use compute_motion to skip over any
2465 text off the left edge of the window. compute_motion may know
2466 tricks to do this faster than we can. */
2467 if (hpos < 0)
2468 {
2469 struct position *left_edge
ca26e1c8
KH
2470 = compute_motion (pos, vpos, hpos, 0,
2471 ZV, vpos, 0,
f4faa47c
JB
2472 width, hscroll, taboffset, w);
2473
2474 /* Retrieve the buffer position and column provided by
2475 compute_motion. We can't assume that the column will be
2476 zero, because you may have multi-column characters crossing
2477 the left margin.
2478
2479 compute_motion may have moved us past the screen position we
2480 requested, if we hit a multi-column character, or the end of
2481 the line. If so, back up. */
2482 if (left_edge->vpos > vpos
2483 || left_edge->hpos > 0)
2484 {
2485 pos = left_edge->bufpos - 1;
2486 hpos = left_edge->prevhpos;
2487 }
2488 else
2489 {
2490 pos = left_edge->bufpos;
2491 hpos = left_edge->hpos;
2492 }
2493 }
2494
2495 desired_glyphs->bufp[vpos] = start;
a2889657 2496 p1 = desired_glyphs->glyphs[vpos] + hpos;
efc63ef0
RS
2497 p1start = p1;
2498 charstart = desired_glyphs->charstarts[vpos] + hpos;
2499 /* In case we don't ever write anything into it... */
a007eef6 2500 desired_glyphs->charstarts[vpos][XFASTINT (w->left)] = -1;
d2f84654
RS
2501 leftmargin = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
2502 endp = leftmargin + width;
a2889657 2503
1c2250c2
JB
2504 /* Arrange the overlays nicely for our purposes. Usually, we call
2505 display_text_line on only one line at a time, in which case this
2506 can't really hurt too much, or we call it on lines which appear
2507 one after another in the buffer, in which case all calls to
2508 recenter_overlay_lists but the first will be pretty cheap. */
2509 recenter_overlay_lists (current_buffer, pos);
2510
a2889657
JB
2511 /* Loop generating characters.
2512 Stop at end of buffer, before newline,
31b24551
JB
2513 if reach or pass continuation column,
2514 or at face change. */
a2889657 2515 pause = pos;
31b24551 2516 next_face_change = pos;
ca26e1c8
KH
2517 next_boundary = pos;
2518 p1prev = p1;
2519 prevpos = pos;
85bcef6c 2520 while (1)
a2889657 2521 {
31b24551 2522 if (pos >= pause)
a2889657 2523 {
ca26e1c8 2524 while (pos == next_boundary)
a2889657 2525 {
ca26e1c8
KH
2526 Lisp_Object position, limit, prop, ww;
2527
2528 /* Display the overlay strings here, unless we're at ZV
2529 and have already displayed the appropriate strings
2530 on an earlier line. */
2531 if (pos < ZV || !zv_strings_seen++)
2532 {
2533 int ovlen;
2534 char *ovstr;
2535 ovlen = overlay_strings (pos, w, &ovstr);
2536 for (; ovlen; ovlen--, ovstr++)
2537 {
2538 if (p1 >= leftmargin && p1 < endp)
2539 *p1 = MAKE_GLYPH (f, *ovstr, current_face);
2540 p1++;
2541 }
2542 }
2543
2544 /* Did we reach point? Record the cursor location. */
2545 if (pos == PT && cursor_vpos < 0)
2546 {
2547 cursor_vpos = vpos;
2548 cursor_hpos = p1 - leftmargin;
2549 }
2550
2551 if (pos >= ZV)
2552 break;
a2889657 2553
c2213350 2554 XSETFASTINT (position, pos);
ca26e1c8
KH
2555 limit = Fnext_overlay_change (position);
2556#ifdef USE_TEXT_PROPERTIES
dfabd9a0
RS
2557 /* This is just an estimate to give reasonable
2558 performance; nothing should go wrong if it is too small. */
fe3d6921 2559 if (XFASTINT (limit) > pos + 50)
c2213350 2560 XSETFASTINT (limit, pos + 50);
ca26e1c8
KH
2561 limit = Fnext_single_property_change (position, Qinvisible,
2562 Fcurrent_buffer (), limit);
2563#endif
2564 next_boundary = XFASTINT (limit);
2565 /* if the `invisible' property is set, we can skip to
2566 the next property change. */
2567 XSETWINDOW (ww, w);
2568 prop = Fget_char_property (position, Qinvisible, ww);
642eefc6 2569 if (TEXT_PROP_MEANS_INVISIBLE (prop))
dfabd9a0 2570 {
ca26e1c8 2571 if (pos < PT && next_boundary >= PT)
dfabd9a0
RS
2572 {
2573 cursor_vpos = vpos;
d2f84654 2574 cursor_hpos = p1 - leftmargin;
dfabd9a0 2575 }
ca26e1c8 2576 pos = next_boundary;
642eefc6
RS
2577 last_invis_skip = pos;
2578 last_invis_prop = prop;
dfabd9a0 2579 }
b0a0fbda 2580 }
ca26e1c8
KH
2581
2582 /* Did we reach point? Record the cursor location. */
2583 if (pos == PT && cursor_vpos < 0)
2584 {
2585 cursor_vpos = vpos;
2586 cursor_hpos = p1 - leftmargin;
2587 }
2588
2589 /* Did we hit the end of the visible region of the buffer?
2590 Stop here. */
2591 if (pos >= ZV)
b0a0fbda 2592 break;
b0a0fbda 2593
87485d6f 2594#ifdef HAVE_FACES
31b24551
JB
2595 /* Did we hit a face change? Figure out what face we should
2596 use now. We also hit this the first time through the
2597 loop, to see what face we should start with. */
b0a0fbda 2598 if (pos >= next_face_change && FRAME_X_P (f))
bd66d1ba
RS
2599 current_face = compute_char_face (f, w, pos,
2600 region_beg, region_end,
efc63ef0 2601 &next_face_change, pos + 50, 0);
9dbd4b48 2602#endif
31b24551 2603
ca26e1c8 2604 pause = ZV;
1c2250c2 2605
ca26e1c8
KH
2606 if (pos < next_boundary && next_boundary < pause)
2607 pause = next_boundary;
1c2250c2
JB
2608 if (pos < next_face_change && next_face_change < pause)
2609 pause = next_face_change;
2610
31b24551
JB
2611 /* Wouldn't you hate to read the next line to someone over
2612 the phone? */
ae3b1442
KH
2613 if (pos < PT && PT < pause)
2614 pause = PT;
a2889657
JB
2615 if (pos < GPT && GPT < pause)
2616 pause = GPT;
2617
2618 p = &FETCH_CHAR (pos);
2619 }
ca26e1c8
KH
2620
2621 /* Do nothing here for a char that's entirely off the left edge. */
2622 if (p1 >= leftmargin)
2623 {
2624 /* For all the glyphs occupied by this character, except for the
2625 first, store -1 in charstarts. */
2626 if (p1 != p1prev)
2627 {
2628 int *p2x = &charstart[(p1prev < leftmargin
2629 ? leftmargin : p1prev)
2630 - p1start];
2631 int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
2632
2633 if (p2x < p2)
2634 *p2x++ = prevpos;
2635 while (p2x < p2)
2636 *p2x++ = -1;
2637 }
2638 }
2639
2640 if (p1 >= endp)
2641 break;
2642
2643 p1prev = p1;
2644
a2889657 2645 c = *p++;
376b0e59
RS
2646 /* Let a display table override all standard display methods. */
2647 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
2648 {
2649 p1 = copy_part_of_rope (f, p1, leftmargin,
2650 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
2651 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
2652 current_face);
2653 }
2654 else if (c >= 040 && c < 0177)
a2889657 2655 {
d2f84654 2656 if (p1 >= leftmargin)
4cdc65eb 2657 *p1 = MAKE_GLYPH (f, c, current_face);
a2889657
JB
2658 p1++;
2659 }
2660 else if (c == '\n')
2661 {
2662 invis = 0;
642eefc6
RS
2663 if (last_invis_skip == pos
2664 && TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (last_invis_prop))
2665 invis = 1;
ca26e1c8 2666 while (pos + 1 < ZV
a2889657 2667 && selective > 0
9f412332 2668 && indented_beyond_p (pos + 1, selective))
a2889657
JB
2669 {
2670 invis = 1;
2671 pos = find_next_newline (pos + 1, 1);
2672 if (FETCH_CHAR (pos - 1) == '\n')
2673 pos--;
2674 }
d2f84654 2675 if (invis && selective_rlen > 0 && p1 >= leftmargin)
a2889657
JB
2676 {
2677 p1 += selective_rlen;
d2f84654 2678 if (p1 - leftmargin > width)
a2889657 2679 p1 = endp;
278feba9 2680 copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
1c2250c2 2681 (p1 - p1prev), current_face);
a2889657 2682 }
87485d6f 2683#ifdef HAVE_FACES
3c5c35c5
JB
2684 /* Draw the face of the newline character as extending all the
2685 way to the end of the frame line. */
2686 if (current_face)
1105ff20
KH
2687 {
2688 if (p1 < leftmargin)
2689 p1 = leftmargin;
2690 while (p1 < endp)
2691 *p1++ = FAST_MAKE_GLYPH (' ', current_face);
2692 }
3c5c35c5 2693#endif
68a37fa8 2694 break;
a2889657
JB
2695 }
2696 else if (c == '\t')
2697 {
2698 do
2699 {
d2f84654 2700 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2701 *p1 = MAKE_GLYPH (f, ' ', current_face);
a2889657
JB
2702 p1++;
2703 }
d2f84654 2704 while ((p1 - leftmargin + taboffset + hscroll - (hscroll > 0))
a2889657
JB
2705 % tab_width);
2706 }
6e8290aa 2707 else if (c == Ctl ('M') && selective == -1)
a2889657
JB
2708 {
2709 pos = find_next_newline (pos, 1);
2710 if (FETCH_CHAR (pos - 1) == '\n')
2711 pos--;
2712 if (selective_rlen > 0)
2713 {
2714 p1 += selective_rlen;
d2f84654 2715 if (p1 - leftmargin > width)
a2889657 2716 p1 = endp;
278feba9 2717 copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
1c2250c2 2718 (p1 - p1prev), current_face);
a2889657 2719 }
87485d6f 2720#ifdef HAVE_FACES
3c5c35c5
JB
2721 /* Draw the face of the newline character as extending all the
2722 way to the end of the frame line. */
2723 if (current_face)
1105ff20
KH
2724 {
2725 if (p1 < leftmargin)
2726 p1 = leftmargin;
2727 while (p1 < endp)
2728 *p1++ = FAST_MAKE_GLYPH (' ', current_face);
2729 }
3c5c35c5 2730#endif
68a37fa8 2731 break;
a2889657 2732 }
a2889657
JB
2733 else if (c < 0200 && ctl_arrow)
2734 {
d2f84654 2735 if (p1 >= leftmargin)
e24c997d 2736 *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
278feba9
RS
2737 ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
2738 current_face);
a2889657 2739 p1++;
d2f84654 2740 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2741 *p1 = MAKE_GLYPH (f, c ^ 0100, current_face);
a2889657
JB
2742 p1++;
2743 }
2744 else
2745 {
d2f84654 2746 if (p1 >= leftmargin)
e24c997d 2747 *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
278feba9
RS
2748 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
2749 current_face);
a2889657 2750 p1++;
d2f84654 2751 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2752 *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face);
a2889657 2753 p1++;
d2f84654 2754 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2755 *p1 = MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face);
a2889657 2756 p1++;
d2f84654 2757 if (p1 >= leftmargin && p1 < endp)
4cdc65eb 2758 *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face);
a2889657
JB
2759 p1++;
2760 }
31b24551 2761
ca26e1c8 2762 prevpos = pos;
a2889657
JB
2763 pos++;
2764 }
2765
2766 val.hpos = - XINT (w->hscroll);
2767 if (val.hpos)
2768 val.hpos++;
2769
2770 val.vpos = 1;
2771
2772 lastpos = pos;
2773
efc63ef0
RS
2774 /* Store 0 in this charstart line for the positions where
2775 there is no character. But do leave what was recorded
2776 for the character that ended the line. */
85bcef6c
RS
2777 /* Add 1 in the endtest to compensate for the fact that ENDP was
2778 made from WIDTH, which is 1 less than the window's actual
2779 internal width. */
a007eef6
RS
2780 i = p1 - p1start + 1;
2781 if (p1 < leftmargin)
2782 i += leftmargin - p1;
2783 for (; i < endp - p1start + 1; i++)
efc63ef0
RS
2784 charstart[i] = 0;
2785
a2889657
JB
2786 /* Handle continuation in middle of a character */
2787 /* by backing up over it */
2788 if (p1 > endp)
2789 {
5fcbb24d
JB
2790 /* Don't back up if we never actually displayed any text.
2791 This occurs when the minibuffer prompt takes up the whole line. */
2792 if (p1prev)
2793 {
2794 /* Start the next line with that same character */
2795 pos--;
2796 /* but at negative hpos, to skip the columns output on this line. */
2797 val.hpos += p1prev - endp;
2798 }
2799
a2889657
JB
2800 /* Keep in this line everything up to the continuation column. */
2801 p1 = endp;
2802 }
2803
2804 /* Finish deciding which character to start the next line on,
2805 and what hpos to start it at.
2806 Also set `lastpos' to the last position which counts as "on this line"
2807 for cursor-positioning. */
2808
2809 if (pos < ZV)
2810 {
2811 if (FETCH_CHAR (pos) == '\n')
dd5f6267
KH
2812 {
2813 /* If stopped due to a newline, start next line after it */
2814 pos++;
2815 /* Check again for hidden lines, in case the newline occurred exactly
2816 at the right margin. */
2817 while (pos < ZV && selective > 0
2818 && indented_beyond_p (pos, selective))
2819 pos = find_next_newline (pos, 1);
2820 }
a2889657
JB
2821 else
2822 /* Stopped due to right margin of window */
2823 {
2824 if (truncate)
2825 {
278feba9 2826 *p1++ = fix_glyph (f, truncator, 0);
a2889657
JB
2827 /* Truncating => start next line after next newline,
2828 and point is on this line if it is before the newline,
2829 and skip none of first char of next line */
dd5f6267
KH
2830 do
2831 pos = find_next_newline (pos, 1);
2832 while (pos < ZV && selective > 0
2833 && indented_beyond_p (pos, selective));
a2889657
JB
2834 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
2835
2836 lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
2837 }
2838 else
2839 {
278feba9 2840 *p1++ = fix_glyph (f, continuer, 0);
a2889657
JB
2841 val.vpos = 0;
2842 lastpos--;
2843 }
2844 }
2845 }
2846
2847 /* If point is at eol or in invisible text at eol,
44fa5b1e 2848 record its frame location now. */
a2889657 2849
ae3b1442 2850 if (start <= PT && PT <= lastpos && cursor_vpos < 0)
a2889657
JB
2851 {
2852 cursor_vpos = vpos;
d2f84654 2853 cursor_hpos = p1 - leftmargin;
a2889657
JB
2854 }
2855
2856 if (cursor_vpos == vpos)
2857 {
2858 if (cursor_hpos < 0) cursor_hpos = 0;
2859 if (cursor_hpos > width) cursor_hpos = width;
2860 cursor_hpos += XFASTINT (w->left);
44fa5b1e 2861 if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
a2889657 2862 {
b5bbc9a5
KH
2863 if (!(cursor_in_echo_area && FRAME_HAS_MINIBUF_P (f)
2864 && EQ (FRAME_MINIBUF_WINDOW (f), minibuf_window)))
2865 {
2866 FRAME_CURSOR_Y (f) = cursor_vpos;
2867 FRAME_CURSOR_X (f) = cursor_hpos;
2868 }
a2889657
JB
2869
2870 if (w == XWINDOW (selected_window))
2871 {
2872 /* Line is not continued and did not start
2873 in middle of character */
2874 if ((hpos - XFASTINT (w->left)
2875 == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
2876 && val.vpos)
2877 {
2878 this_line_bufpos = start;
2879 this_line_buffer = current_buffer;
2880 this_line_vpos = cursor_vpos;
2881 this_line_start_hpos = hpos;
2882 this_line_endpos = Z - lastpos;
2883 }
2884 else
2885 this_line_bufpos = 0;
2886 }
2887 }
2888 }
2889
2890 /* If hscroll and line not empty, insert truncation-at-left marker */
2891 if (hscroll && lastpos != start)
2892 {
d2f84654
RS
2893 *leftmargin = fix_glyph (f, truncator, 0);
2894 if (p1 <= leftmargin)
2895 p1 = leftmargin + 1;
a2889657
JB
2896 }
2897
44fa5b1e 2898 if (XFASTINT (w->width) + XFASTINT (w->left) != FRAME_WIDTH (f))
a2889657
JB
2899 {
2900 endp++;
d2f84654 2901 if (p1 < leftmargin) p1 = leftmargin;
a2889657 2902 while (p1 < endp) *p1++ = SPACEGLYPH;
b1d1124b 2903
88f22aff
JB
2904 /* Don't draw vertical bars if we're using scroll bars. They're
2905 covered up by the scroll bars, and it's distracting to see
2906 them when the scroll bar windows are flickering around to be
b1d1124b 2907 reconfigured. */
88f22aff 2908 *p1++ = (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
a45e35e1
JB
2909 ? ' '
2910 : (dp && INTEGERP (DISP_BORDER_GLYPH (dp))
2911 ? DISP_BORDER_GLYPH (dp)
2912 : '|'));
a2889657
JB
2913 }
2914 desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
2915 p1 - desired_glyphs->glyphs[vpos]);
2916 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
2917
2918 /* If the start of this line is the overlay arrow-position,
2919 then put the arrow string into the display-line. */
2920
e24c997d 2921 if (MARKERP (Voverlay_arrow_position)
a2889657
JB
2922 && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
2923 && start == marker_position (Voverlay_arrow_position)
e24c997d 2924 && STRINGP (Voverlay_arrow_string)
a2889657
JB
2925 && ! overlay_arrow_seen)
2926 {
2927 unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
2928 int i;
2929 int len = XSTRING (Voverlay_arrow_string)->size;
142be3dd 2930 int arrow_end;
a2889657 2931
b1d1124b
JB
2932 if (len > width)
2933 len = width;
87485d6f 2934#ifdef HAVE_FACES
c4628384
RS
2935 if (!NULL_INTERVAL_P (XSTRING (Voverlay_arrow_string)->intervals))
2936 {
2937 /* If the arrow string has text props, obey them when displaying. */
2938 for (i = 0; i < len; i++)
2939 {
2940 int c = p[i];
2941 Lisp_Object face, ilisp;
2942 int newface;
2943
c2213350 2944 XSETFASTINT (ilisp, i);
c4628384
RS
2945 face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string);
2946 newface = compute_glyph_face_1 (f, face, 0);
2947 leftmargin[i] = FAST_MAKE_GLYPH (c, newface);
2948 }
2949 }
2950 else
87485d6f 2951#endif /* HAVE_FACES */
c4628384
RS
2952 {
2953 for (i = 0; i < len; i++)
2954 leftmargin[i] = p[i];
2955 }
142be3dd
JB
2956
2957 /* Bug in SunOS 4.1.1 compiler requires this intermediate variable. */
d2f84654 2958 arrow_end = (leftmargin - desired_glyphs->glyphs[vpos]) + len;
142be3dd
JB
2959 if (desired_glyphs->used[vpos] < arrow_end)
2960 desired_glyphs->used[vpos] = arrow_end;
a2889657
JB
2961
2962 overlay_arrow_seen = 1;
2963 }
2964
2965 val.bufpos = pos;
2966 val_display_text_line = val;
2967 return &val_display_text_line;
2968}
2969\f
7ce2c095
RS
2970/* Redisplay the menu bar in the frame for window W. */
2971
2972static void
2973display_menu_bar (w)
2974 struct window *w;
2975{
2976 Lisp_Object items, tail;
2977 register int vpos = 0;
2978 register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2979 int maxendcol = FRAME_WIDTH (f);
2980 int hpos = 0;
8351baf2 2981 int i;
7ce2c095 2982
76412d64 2983#ifndef USE_X_TOOLKIT
7ce2c095
RS
2984 if (FRAME_MENU_BAR_LINES (f) <= 0)
2985 return;
2986
2987 get_display_line (f, vpos, 0);
2988
8351baf2
RS
2989 items = FRAME_MENU_BAR_ITEMS (f);
2990 for (i = 0; i < XVECTOR (items)->size; i += 3)
7ce2c095 2991 {
8351baf2
RS
2992 Lisp_Object pos, string;
2993 string = XVECTOR (items)->contents[i + 1];
2994 if (NILP (string))
2995 break;
2d66ad19 2996
c2213350 2997 XSETFASTINT (XVECTOR (items)->contents[i + 2], hpos);
7ce2c095
RS
2998
2999 if (hpos < maxendcol)
3000 hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
3001 XSTRING (string)->data,
90adcf20 3002 XSTRING (string)->size,
278feba9 3003 hpos, 0, 0, hpos, maxendcol);
6b1bbc46 3004 /* Put a space between items. */
2d66ad19
RS
3005 if (hpos < maxendcol)
3006 {
6b1bbc46 3007 int hpos1 = hpos + 1;
278feba9 3008 hpos = display_string (w, vpos, "", 0, hpos, 0, 0,
2d66ad19
RS
3009 min (hpos1, maxendcol), maxendcol);
3010 }
7ce2c095
RS
3011 }
3012
3013 FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
3014 FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
2d66ad19
RS
3015
3016 /* Fill out the line with spaces. */
3017 if (maxendcol > hpos)
278feba9 3018 hpos = display_string (w, vpos, "", 0, hpos, 0, 0, maxendcol, maxendcol);
db6f348c
JB
3019
3020 /* Clear the rest of the lines allocated to the menu bar. */
3021 vpos++;
3022 while (vpos < FRAME_MENU_BAR_LINES (f))
3023 get_display_line (f, vpos++, 0);
76412d64 3024#endif /* not USE_X_TOOLKIT */
7ce2c095
RS
3025}
3026\f
a2889657
JB
3027/* Display the mode line for window w */
3028
3029static void
3030display_mode_line (w)
3031 struct window *w;
3032{
3033 register int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
3034 register int left = XFASTINT (w->left);
3035 register int right = XFASTINT (w->width) + left;
44fa5b1e 3036 register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
a2889657 3037
aa6d10fa 3038 line_number_displayed = 0;
155ef550 3039 w->column_number_displayed = Qnil;
aa6d10fa 3040
44fa5b1e 3041 get_display_line (f, vpos, left);
03b294dc
RS
3042
3043 /* Temporarily make frame F's kboard the current kboard
3044 so that kboard-local variables in the mode_line_format
3045 will get the right values. */
3046 push_frame_kboard (f);
3047
3048 display_mode_element (w, vpos, left, 0, right, right,
3049 current_buffer->mode_line_format);
3050
3051 pop_frame_kboard ();
3052
44fa5b1e 3053 FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
a2889657
JB
3054
3055 /* Make the mode line inverse video if the entire line
3056 is made of mode lines.
3057 I.e. if this window is full width,
3058 or if it is the child of a full width window
3059 (which implies that that window is split side-by-side
3060 and the rest of this line is mode lines of the sibling windows). */
44fa5b1e
JB
3061 if (XFASTINT (w->width) == FRAME_WIDTH (f)
3062 || XFASTINT (XWINDOW (w->parent)->width) == FRAME_WIDTH (f))
3063 FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
87485d6f 3064#ifdef HAVE_FACES
03b294dc 3065 else if (! FRAME_TERMCAP_P (f) && mode_line_inverse_video)
d7eb09a0
RS
3066 {
3067 /* For a partial width window, explicitly set face of each glyph. */
3068 int i;
3069 GLYPH *ptr = FRAME_DESIRED_GLYPHS (f)->glyphs[vpos];
3070 for (i = left; i < right; ++i)
4cdc65eb 3071 ptr[i] = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (ptr[i]), 1);
d7eb09a0 3072 }
4cdc65eb 3073#endif
a2889657
JB
3074}
3075
3076/* Contribute ELT to the mode line for window W.
3077 How it translates into text depends on its data type.
3078
3079 VPOS is the position of the mode line being displayed.
3080
44fa5b1e 3081 HPOS is the position (absolute on frame) where this element's text
a2889657
JB
3082 should start. The output is truncated automatically at the right
3083 edge of window W.
3084
3085 DEPTH is the depth in recursion. It is used to prevent
3086 infinite recursion here.
3087
3088 MINENDCOL is the hpos before which the element may not end.
3089 The element is padded at the right with spaces if nec
3090 to reach this column.
3091
3092 MAXENDCOL is the hpos past which this element may not extend.
3093 If MINENDCOL is > MAXENDCOL, MINENDCOL takes priority.
3094 (This is necessary to make nested padding and truncation work.)
3095
3096 Returns the hpos of the end of the text generated by ELT.
3097 The next element will receive that value as its HPOS arg,
3098 so as to concatenate the elements. */
3099
3100static int
3101display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
3102 struct window *w;
3103 register int vpos, hpos;
3104 int depth;
3105 int minendcol;
3106 register int maxendcol;
3107 register Lisp_Object elt;
3108{
3109 tail_recurse:
3110 if (depth > 10)
3111 goto invalid;
3112
3113 depth++;
3114
0220c518 3115 switch (SWITCH_ENUM_CAST (XTYPE (elt)))
a2889657
JB
3116 {
3117 case Lisp_String:
3118 {
3119 /* A string: output it and check for %-constructs within it. */
3120 register unsigned char c;
3121 register unsigned char *this = XSTRING (elt)->data;
3122
3123 while (hpos < maxendcol && *this)
3124 {
3125 unsigned char *last = this;
3126 while ((c = *this++) != '\0' && c != '%')
3127 ;
3128 if (this - 1 != last)
3129 {
3130 register int lim = --this - last + hpos;
d39b6696
KH
3131 if (frame_title_ptr)
3132 hpos = store_frame_title (last, hpos, min (lim, maxendcol));
3133 else
3134 hpos = display_string (w, vpos, last, -1, hpos, 0, 1,
3135 hpos, min (lim, maxendcol));
a2889657
JB
3136 }
3137 else /* c == '%' */
3138 {
3139 register int spec_width = 0;
3140
3141 /* We can't allow -ve args due to the "%-" construct */
3142 /* Argument specifies minwidth but not maxwidth
3143 (maxwidth can be specified by
3144 (<negative-number> . <stuff>) mode-line elements) */
3145
3146 while ((c = *this++) >= '0' && c <= '9')
3147 {
3148 spec_width = spec_width * 10 + (c - '0');
3149 }
3150
3151 spec_width += hpos;
3152 if (spec_width > maxendcol)
3153 spec_width = maxendcol;
3154
3155 if (c == 'M')
3156 hpos = display_mode_element (w, vpos, hpos, depth,
3157 spec_width, maxendcol,
3158 Vglobal_mode_string);
3159 else if (c != 0)
d39b6696
KH
3160 {
3161 char *spec = decode_mode_spec (w, c, maxendcol - hpos);
3162 if (frame_title_ptr)
3163 hpos = store_frame_title (spec, spec_width, maxendcol);
3164 else
3165 hpos = display_string (w, vpos, spec, -1,
3166 hpos, 0, 1,
3167 spec_width, maxendcol);
3168 }
a2889657
JB
3169 }
3170 }
3171 }
3172 break;
3173
3174 case Lisp_Symbol:
3175 /* A symbol: process the value of the symbol recursively
3176 as if it appeared here directly. Avoid error if symbol void.
3177 Special case: if value of symbol is a string, output the string
3178 literally. */
3179 {
3180 register Lisp_Object tem;
3181 tem = Fboundp (elt);
265a9e55 3182 if (!NILP (tem))
a2889657
JB
3183 {
3184 tem = Fsymbol_value (elt);
3185 /* If value is a string, output that string literally:
3186 don't check for % within it. */
e24c997d 3187 if (STRINGP (tem))
d39b6696
KH
3188 {
3189 if (frame_title_ptr)
3190 hpos = store_frame_title (XSTRING (tem)->data,
3191 minendcol, maxendcol);
3192 else
3193 hpos = display_string (w, vpos, XSTRING (tem)->data,
3194 XSTRING (tem)->size,
3195 hpos, 0, 1, minendcol, maxendcol);
3196 }
a2889657
JB
3197 /* Give up right away for nil or t. */
3198 else if (!EQ (tem, elt))
3199 { elt = tem; goto tail_recurse; }
3200 }
3201 }
3202 break;
3203
3204 case Lisp_Cons:
3205 {
3206 register Lisp_Object car, tem;
3207
3208 /* A cons cell: three distinct cases.
3209 If first element is a string or a cons, process all the elements
3210 and effectively concatenate them.
3211 If first element is a negative number, truncate displaying cdr to
3212 at most that many characters. If positive, pad (with spaces)
3213 to at least that many characters.
3214 If first element is a symbol, process the cadr or caddr recursively
3215 according to whether the symbol's value is non-nil or nil. */
3216 car = XCONS (elt)->car;
e24c997d 3217 if (SYMBOLP (car))
a2889657
JB
3218 {
3219 tem = Fboundp (car);
3220 elt = XCONS (elt)->cdr;
e24c997d 3221 if (!CONSP (elt))
a2889657
JB
3222 goto invalid;
3223 /* elt is now the cdr, and we know it is a cons cell.
3224 Use its car if CAR has a non-nil value. */
265a9e55 3225 if (!NILP (tem))
a2889657
JB
3226 {
3227 tem = Fsymbol_value (car);
265a9e55 3228 if (!NILP (tem))
a2889657
JB
3229 { elt = XCONS (elt)->car; goto tail_recurse; }
3230 }
3231 /* Symbol's value is nil (or symbol is unbound)
3232 Get the cddr of the original list
3233 and if possible find the caddr and use that. */
3234 elt = XCONS (elt)->cdr;
265a9e55 3235 if (NILP (elt))
a2889657 3236 break;
e24c997d 3237 else if (!CONSP (elt))
a2889657
JB
3238 goto invalid;
3239 elt = XCONS (elt)->car;
3240 goto tail_recurse;
3241 }
e24c997d 3242 else if (INTEGERP (car))
a2889657
JB
3243 {
3244 register int lim = XINT (car);
3245 elt = XCONS (elt)->cdr;
3246 if (lim < 0)
3247 /* Negative int means reduce maximum width.
3248 DO NOT change MINENDCOL here!
3249 (20 -10 . foo) should truncate foo to 10 col
3250 and then pad to 20. */
3251 maxendcol = min (maxendcol, hpos - lim);
3252 else if (lim > 0)
3253 {
3254 /* Padding specified. Don't let it be more than
3255 current maximum. */
3256 lim += hpos;
3257 if (lim > maxendcol)
3258 lim = maxendcol;
3259 /* If that's more padding than already wanted, queue it.
3260 But don't reduce padding already specified even if
3261 that is beyond the current truncation point. */
3262 if (lim > minendcol)
3263 minendcol = lim;
3264 }
3265 goto tail_recurse;
3266 }
e24c997d 3267 else if (STRINGP (car) || CONSP (car))
a2889657
JB
3268 {
3269 register int limit = 50;
3270 /* LIMIT is to protect against circular lists. */
e24c997d 3271 while (CONSP (elt) && --limit > 0
a2889657
JB
3272 && hpos < maxendcol)
3273 {
3274 hpos = display_mode_element (w, vpos, hpos, depth,
3275 hpos, maxendcol,
3276 XCONS (elt)->car);
3277 elt = XCONS (elt)->cdr;
3278 }
3279 }
3280 }
3281 break;
3282
3283 default:
3284 invalid:
d39b6696
KH
3285 if (frame_title_ptr)
3286 hpos = store_frame_title ("*invalid*", minendcol, maxendcol);
3287 else
3288 hpos = display_string (w, vpos, "*invalid*", -1, hpos, 0, 1,
3289 minendcol, maxendcol);
3290 return hpos;
a2889657
JB
3291 }
3292
a2889657 3293 if (minendcol > hpos)
d39b6696
KH
3294 if (frame_title_ptr)
3295 hpos = store_frame_title ("", minendcol, maxendcol);
3296 else
3297 hpos = display_string (w, vpos, "", 0, hpos, 0, 1, minendcol, maxendcol);
a2889657
JB
3298 return hpos;
3299}
3300\f
3301/* Return a string for the output of a mode line %-spec for window W,
3302 generated by character C and width MAXWIDTH. */
3303
11e82b76
JB
3304static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
3305
a2889657
JB
3306static char *
3307decode_mode_spec (w, c, maxwidth)
3308 struct window *w;
3309 register char c;
3310 register int maxwidth;
3311{
0b67772d 3312 Lisp_Object obj;
44fa5b1e
JB
3313 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
3314 char *decode_mode_spec_buf = (char *) FRAME_TEMP_GLYPHS (f)->total_contents;
d39b6696 3315 struct buffer *b = XBUFFER (w->buffer);
a2889657 3316
0b67772d 3317 obj = Qnil;
44fa5b1e
JB
3318 if (maxwidth > FRAME_WIDTH (f))
3319 maxwidth = FRAME_WIDTH (f);
a2889657
JB
3320
3321 switch (c)
3322 {
1af9f229
RS
3323 case '*':
3324 if (!NILP (b->read_only))
3325 return "%";
3326 if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
3327 return "*";
3328 return "-";
3329
3330 case '+':
3331 /* This differs from %* only for a modified read-only buffer. */
3332 if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
3333 return "*";
3334 if (!NILP (b->read_only))
3335 return "%";
3336 return "-";
3337
3338 case '&':
3339 /* This differs from %* in ignoring read-only-ness. */
3340 if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
3341 return "*";
3342 return "-";
3343
3344 case '%':
3345 return "%";
3346
3347 case '[':
3348 {
3349 int i;
3350 char *p;
3351
3352 if (command_loop_level > 5)
3353 return "[[[... ";
3354 p = decode_mode_spec_buf;
3355 for (i = 0; i < command_loop_level; i++)
3356 *p++ = '[';
3357 *p = 0;
3358 return decode_mode_spec_buf;
3359 }
3360
3361 case ']':
3362 {
3363 int i;
3364 char *p;
3365
3366 if (command_loop_level > 5)
3367 return " ...]]]";
3368 p = decode_mode_spec_buf;
3369 for (i = 0; i < command_loop_level; i++)
3370 *p++ = ']';
3371 *p = 0;
3372 return decode_mode_spec_buf;
3373 }
3374
3375 case '-':
3376 {
3377 register char *p;
3378 register int i;
3379
3380 if (maxwidth < sizeof (lots_of_dashes))
3381 return lots_of_dashes;
3382 else
3383 {
3384 for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
3385 *p++ = '-';
3386 *p = '\0';
3387 }
3388 return decode_mode_spec_buf;
3389 }
3390
a2889657 3391 case 'b':
d39b6696 3392 obj = b->name;
a2889657
JB
3393#if 0
3394 if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
3395 {
3396 bcopy (XSTRING (obj)->data, decode_mode_spec_buf, maxwidth - 1);
3397 decode_mode_spec_buf[maxwidth - 1] = '\\';
3398 decode_mode_spec_buf[maxwidth] = '\0';
3399 return decode_mode_spec_buf;
3400 }
3401#endif
3402 break;
3403
1af9f229
RS
3404 case 'c':
3405 {
3406 int col = current_column ();
3407 XSETFASTINT (w->column_number_displayed, col);
3408 sprintf (decode_mode_spec_buf, "%d", col);
3409 return decode_mode_spec_buf;
3410 }
3411
3412 case 'F':
3413 /* %F displays the frame name. */
3414 return (char *) XSTRING (selected_frame->name)->data;
3415
a2889657 3416 case 'f':
d39b6696 3417 obj = b->filename;
a2889657 3418#if 0
265a9e55 3419 if (NILP (obj))
a2889657 3420 return "[none]";
e24c997d 3421 else if (STRINGP (obj) && XSTRING (obj)->size > maxwidth)
a2889657
JB
3422 {
3423 bcopy ("...", decode_mode_spec_buf, 3);
3424 bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
3425 decode_mode_spec_buf + 3, maxwidth - 3);
3426 return decode_mode_spec_buf;
3427 }
3428#endif
3429 break;
3430
aa6d10fa
RS
3431 case 'l':
3432 {
3433 int startpos = marker_position (w->start);
3434 int line, linepos, topline;
3435 int nlines, junk;
3436 Lisp_Object tem;
3437 int height = XFASTINT (w->height);
3438
3439 /* If we decided that this buffer isn't suitable for line numbers,
3440 don't forget that too fast. */
3441 if (EQ (w->base_line_pos, w->buffer))
3442 return "??";
3443
3444 /* If the buffer is very big, don't waste time. */
d39b6696 3445 if (BUF_ZV (b) - BUF_BEGV (b) > line_number_display_limit)
aa6d10fa
RS
3446 {
3447 w->base_line_pos = Qnil;
3448 w->base_line_number = Qnil;
3449 return "??";
3450 }
3451
3452 if (!NILP (w->base_line_number)
3453 && !NILP (w->base_line_pos)
3454 && XFASTINT (w->base_line_pos) <= marker_position (w->start))
3455 {
3456 line = XFASTINT (w->base_line_number);
3457 linepos = XFASTINT (w->base_line_pos);
3458 }
3459 else
3460 {
3461 line = 1;
d39b6696 3462 linepos = BUF_BEGV (b);
aa6d10fa
RS
3463 }
3464
3465 /* Count lines from base line to window start position. */
3466 nlines = display_count_lines (linepos, startpos, startpos, &junk);
3467
3468 topline = nlines + line;
3469
3470 /* Determine a new base line, if the old one is too close
3471 or too far away, or if we did not have one.
3472 "Too close" means it's plausible a scroll-down would
3473 go back past it. */
d39b6696 3474 if (startpos == BUF_BEGV (b))
aa6d10fa 3475 {
c2213350
KH
3476 XSETFASTINT (w->base_line_number, topline);
3477 XSETFASTINT (w->base_line_pos, BUF_BEGV (b));
aa6d10fa
RS
3478 }
3479 else if (nlines < height + 25 || nlines > height * 3 + 50
d39b6696 3480 || linepos == BUF_BEGV (b))
aa6d10fa 3481 {
d39b6696 3482 int limit = BUF_BEGV (b);
aa6d10fa
RS
3483 int position;
3484 int distance = (height * 2 + 30) * 200;
3485
3486 if (startpos - distance > limit)
3487 limit = startpos - distance;
3488
3489 nlines = display_count_lines (startpos, limit,
3490 -(height * 2 + 30),
3491 &position);
3492 /* If we couldn't find the lines we wanted within
3493 200 chars per line,
3494 give up on line numbers for this window. */
3495 if (position == startpos - distance)
3496 {
3497 w->base_line_pos = w->buffer;
3498 w->base_line_number = Qnil;
3499 return "??";
3500 }
3501
c2213350
KH
3502 XSETFASTINT (w->base_line_number, topline - nlines);
3503 XSETFASTINT (w->base_line_pos, position);
aa6d10fa
RS
3504 }
3505
3506 /* Now count lines from the start pos to point. */
3507 nlines = display_count_lines (startpos, PT, PT, &junk);
3508
3509 /* Record that we did display the line number. */
3510 line_number_displayed = 1;
3511
3512 /* Make the string to show. */
3513 sprintf (decode_mode_spec_buf, "%d", topline + nlines);
3514 return decode_mode_spec_buf;
3515 }
3516 break;
3517
a2889657 3518 case 'm':
d39b6696 3519 obj = b->mode_name;
a2889657
JB
3520 break;
3521
3522 case 'n':
d39b6696 3523 if (BUF_BEGV (b) > BUF_BEG (b) || BUF_ZV (b) < BUF_Z (b))
a2889657
JB
3524 return " Narrow";
3525 break;
3526
a2889657
JB
3527 case 'p':
3528 {
3529 int pos = marker_position (w->start);
d39b6696 3530 int total = BUF_ZV (b) - BUF_BEGV (b);
a2889657 3531
d39b6696 3532 if (XFASTINT (w->window_end_pos) <= BUF_Z (b) - BUF_ZV (b))
a2889657 3533 {
d39b6696 3534 if (pos <= BUF_BEGV (b))
a2889657
JB
3535 return "All";
3536 else
3537 return "Bottom";
3538 }
d39b6696 3539 else if (pos <= BUF_BEGV (b))
a2889657
JB
3540 return "Top";
3541 else
3542 {
d39b6696 3543 total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total;
a2889657
JB
3544 /* We can't normally display a 3-digit number,
3545 so get us a 2-digit number that is close. */
3546 if (total == 100)
3547 total = 99;
3548 sprintf (decode_mode_spec_buf, "%2d%%", total);
3549 return decode_mode_spec_buf;
3550 }
3551 }
3552
8ffcb79f
RS
3553 /* Display percentage of size above the bottom of the screen. */
3554 case 'P':
3555 {
3556 int toppos = marker_position (w->start);
d39b6696
KH
3557 int botpos = BUF_Z (b) - XFASTINT (w->window_end_pos);
3558 int total = BUF_ZV (b) - BUF_BEGV (b);
8ffcb79f 3559
d39b6696 3560 if (botpos >= BUF_ZV (b))
8ffcb79f 3561 {
d39b6696 3562 if (toppos <= BUF_BEGV (b))
8ffcb79f
RS
3563 return "All";
3564 else
3565 return "Bottom";
3566 }
3567 else
3568 {
d39b6696 3569 total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total;
8ffcb79f
RS
3570 /* We can't normally display a 3-digit number,
3571 so get us a 2-digit number that is close. */
3572 if (total == 100)
3573 total = 99;
d39b6696 3574 if (toppos <= BUF_BEGV (b))
8ffcb79f
RS
3575 sprintf (decode_mode_spec_buf, "Top%2d%%", total);
3576 else
3577 sprintf (decode_mode_spec_buf, "%2d%%", total);
3578 return decode_mode_spec_buf;
3579 }
3580 }
3581
1af9f229
RS
3582 case 's':
3583 /* status of process */
3584 obj = Fget_buffer_process (w->buffer);
3585 if (NILP (obj))
3586 return "no process";
3587#ifdef subprocesses
3588 obj = Fsymbol_name (Fprocess_status (obj));
3589#endif
3590 break;
d39b6696 3591
1af9f229
RS
3592 case 't': /* indicate TEXT or BINARY */
3593#ifdef MODE_LINE_BINARY_TEXT
3594 return MODE_LINE_BINARY_TEXT (b);
3595#else
3596 return "T";
3597#endif
a2889657 3598 }
d39b6696 3599
e24c997d 3600 if (STRINGP (obj))
a2889657
JB
3601 return (char *) XSTRING (obj)->data;
3602 else
3603 return "";
3604}
59b49f63
RS
3605\f
3606/* Search for COUNT instances of a line boundary, which means either a
3607 newline or (if selective display enabled) a carriage return.
3608 Start at START. If COUNT is negative, search backwards.
3609
3610 If we find COUNT instances, set *SHORTAGE to zero, and return the
3611 position after the COUNTth match. Note that for reverse motion
3612 this is not the same as the usual convention for Emacs motion commands.
3613
3614 If we don't find COUNT instances before reaching the end of the
3615 buffer (or the beginning, if scanning backwards), set *SHORTAGE to
3616 the number of line boundaries left unfound, and return the end of the
3617 buffer we bumped up against. */
3618
3619static int
3620display_scan_buffer (start, count, shortage)
3621 int *shortage, start;
3622 register int count;
3623{
3624 int limit = ((count > 0) ? ZV - 1 : BEGV);
3625 int direction = ((count > 0) ? 1 : -1);
3626
3627 register unsigned char *cursor;
3628 unsigned char *base;
3629
3630 register int ceiling;
3631 register unsigned char *ceiling_addr;
3632
3633 /* If we are not in selective display mode,
3634 check only for newlines. */
3635 if (! (!NILP (current_buffer->selective_display)
3636 && !INTEGERP (current_buffer->selective_display)))
ae474ea9 3637 return scan_buffer ('\n', start, 0, count, shortage, 0);
59b49f63
RS
3638
3639 /* The code that follows is like scan_buffer
3640 but checks for either newline or carriage return. */
3641
3642 if (shortage != 0)
3643 *shortage = 0;
3644
3645 if (count > 0)
3646 while (start != limit + 1)
3647 {
3648 ceiling = BUFFER_CEILING_OF (start);
3649 ceiling = min (limit, ceiling);
3650 ceiling_addr = &FETCH_CHAR (ceiling) + 1;
3651 base = (cursor = &FETCH_CHAR (start));
3652 while (1)
3653 {
3654 while (*cursor != '\n' && *cursor != 015 && ++cursor != ceiling_addr)
3655 ;
3656 if (cursor != ceiling_addr)
3657 {
3658 if (--count == 0)
3659 {
3660 immediate_quit = 0;
3661 return (start + cursor - base + 1);
3662 }
3663 else
3664 if (++cursor == ceiling_addr)
3665 break;
3666 }
3667 else
3668 break;
3669 }
3670 start += cursor - base;
3671 }
3672 else
3673 {
3674 start--; /* first character we scan */
3675 while (start > limit - 1)
3676 { /* we WILL scan under start */
3677 ceiling = BUFFER_FLOOR_OF (start);
3678 ceiling = max (limit, ceiling);
3679 ceiling_addr = &FETCH_CHAR (ceiling) - 1;
3680 base = (cursor = &FETCH_CHAR (start));
3681 cursor++;
3682 while (1)
3683 {
3684 while (--cursor != ceiling_addr
3685 && *cursor != '\n' && *cursor != 015)
3686 ;
3687 if (cursor != ceiling_addr)
3688 {
3689 if (++count == 0)
3690 {
3691 immediate_quit = 0;
3692 return (start + cursor - base + 1);
3693 }
3694 }
3695 else
3696 break;
3697 }
3698 start += cursor - base;
3699 }
3700 }
3701
3702 if (shortage != 0)
3703 *shortage = count * direction;
3704 return (start + ((direction == 1 ? 0 : 1)));
3705}
aa6d10fa
RS
3706
3707/* Count up to N lines starting from FROM.
3708 But don't go beyond LIMIT.
3709 Return the number of lines thus found (always positive).
3710 Store the position after what was found into *POS_PTR. */
3711
3712static int
3713display_count_lines (from, limit, n, pos_ptr)
3714 int from, limit, n;
3715 int *pos_ptr;
3716{
3717 int oldbegv = BEGV;
3718 int oldzv = ZV;
3719 int shortage = 0;
3720
3721 if (limit < from)
3722 BEGV = limit;
3723 else
3724 ZV = limit;
3725
59b49f63 3726 *pos_ptr = display_scan_buffer (from, n, &shortage);
aa6d10fa
RS
3727
3728 ZV = oldzv;
3729 BEGV = oldbegv;
3730
3731 if (n < 0)
3732 /* When scanning backwards, scan_buffer stops *after* the last newline
3733 it finds, but does count it. Compensate for that. */
3734 return - n - shortage - (*pos_ptr != limit);
3735 return n - shortage;
3736}
a2889657
JB
3737\f
3738/* Display STRING on one line of window W, starting at HPOS.
3739 Display at position VPOS. Caller should have done get_display_line.
11e82b76 3740 If VPOS == -1, display it as the current frame's title.
90adcf20 3741 LENGTH is the length of STRING, or -1 meaning STRING is null-terminated.
a2889657
JB
3742
3743 TRUNCATE is GLYPH to display at end if truncated. Zero for none.
3744
3745 MINCOL is the first column ok to end at. (Pad with spaces to this col.)
3746 MAXCOL is the last column ok to end at. Truncate here.
3747 -1 for MINCOL or MAXCOL means no explicit minimum or maximum.
44fa5b1e 3748 Both count from the left edge of the frame, as does HPOS.
a2889657
JB
3749 The right edge of W is an implicit maximum.
3750 If TRUNCATE is nonzero, the implicit maximum is one column before the edge.
3751
278feba9
RS
3752 OBEY_WINDOW_WIDTH says to put spaces or vertical bars
3753 at the place where the current window ends in this line
3754 and not display anything beyond there. Otherwise, only MAXCOL
3755 controls where to stop output.
3756
3757 Returns ending hpos. */
a2889657
JB
3758
3759static int
278feba9
RS
3760display_string (w, vpos, string, length, hpos, truncate,
3761 obey_window_width, mincol, maxcol)
a2889657
JB
3762 struct window *w;
3763 unsigned char *string;
90adcf20 3764 int length;
a2889657
JB
3765 int vpos, hpos;
3766 GLYPH truncate;
278feba9 3767 int obey_window_width;
a2889657
JB
3768 int mincol, maxcol;
3769{
3770 register int c;
3771 register GLYPH *p1;
3772 int hscroll = XINT (w->hscroll);
253c7d2f 3773 int tab_width = XINT (XBUFFER (w->buffer)->tab_width);
a2889657
JB
3774 register GLYPH *start;
3775 register GLYPH *end;
b1d1124b
JB
3776 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
3777 struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
a2889657
JB
3778 GLYPH *p1start = desired_glyphs->glyphs[vpos] + hpos;
3779 int window_width = XFASTINT (w->width);
3780
3781 /* Use the standard display table, not the window's display table.
3782 We don't want the mode line in rot13. */
3783 register struct Lisp_Vector *dp = 0;
efc63ef0 3784 int i;
a2889657 3785
e24c997d 3786 if (VECTORP (Vstandard_display_table)
a2889657
JB
3787 && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
3788 dp = XVECTOR (Vstandard_display_table);
3789
54ff581a 3790 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
a2889657
JB
3791
3792 p1 = p1start;
3793 start = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
a2889657 3794
278feba9 3795 if (obey_window_width)
b1d1124b 3796 {
278feba9
RS
3797 end = start + window_width - (truncate != 0);
3798
3799 if ((window_width + XFASTINT (w->left)) != FRAME_WIDTH (f))
b1d1124b 3800 {
278feba9
RS
3801 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
3802 {
3803 int i;
b1d1124b 3804
5802e919 3805 for (i = 0; i < FRAME_SCROLL_BAR_COLS (f); i++)
278feba9
RS
3806 *end-- = ' ';
3807 }
3808 else
3809 *end-- = '|';
b1d1124b 3810 }
b1d1124b 3811 }
a2889657 3812
278feba9
RS
3813 if (! obey_window_width
3814 || (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol))
a2889657 3815 end = desired_glyphs->glyphs[vpos] + maxcol;
278feba9 3816
efc63ef0 3817 /* Store 0 in charstart for these columns. */
bd5dec8e 3818 for (i = (hpos >= 0 ? hpos : 0); i < end - p1start + hpos; i++)
efc63ef0
RS
3819 desired_glyphs->charstarts[vpos][i] = 0;
3820
a2889657
JB
3821 if (maxcol >= 0 && mincol > maxcol)
3822 mincol = maxcol;
3823
3824 while (p1 < end)
3825 {
90adcf20
RS
3826 if (length == 0)
3827 break;
a2889657 3828 c = *string++;
90adcf20
RS
3829 /* Specified length. */
3830 if (length >= 0)
3831 length--;
3832 /* Unspecified length (null-terminated string). */
3833 else if (c == 0)
3834 break;
3835
376b0e59
RS
3836 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
3837 {
3838 p1 = copy_part_of_rope (f, p1, start,
3839 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
3840 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
3841 0);
3842 }
3843 else if (c >= 040 && c < 0177)
a2889657
JB
3844 {
3845 if (p1 >= start)
3846 *p1 = c;
3847 p1++;
3848 }
3849 else if (c == '\t')
3850 {
3851 do
3852 {
3853 if (p1 >= start && p1 < end)
3854 *p1 = SPACEGLYPH;
3855 p1++;
3856 }
3857 while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
3858 }
ded34426 3859 else if (c < 0200 && ! NILP (buffer_defaults.ctl_arrow))
a2889657
JB
3860 {
3861 if (p1 >= start)
e24c997d 3862 *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
278feba9
RS
3863 ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
3864 0);
a2889657 3865 p1++;
6e8290aa 3866 if (p1 >= start && p1 < end)
a2889657
JB
3867 *p1 = c ^ 0100;
3868 p1++;
3869 }
3870 else
3871 {
3872 if (p1 >= start)
e24c997d 3873 *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
278feba9
RS
3874 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
3875 0);
a2889657 3876 p1++;
6e8290aa 3877 if (p1 >= start && p1 < end)
a2889657
JB
3878 *p1 = (c >> 6) + '0';
3879 p1++;
6e8290aa 3880 if (p1 >= start && p1 < end)
a2889657
JB
3881 *p1 = (7 & (c >> 3)) + '0';
3882 p1++;
6e8290aa 3883 if (p1 >= start && p1 < end)
a2889657
JB
3884 *p1 = (7 & c) + '0';
3885 p1++;
3886 }
3887 }
3888
90adcf20 3889 if (c && length > 0)
a2889657
JB
3890 {
3891 p1 = end;
278feba9 3892 if (truncate) *p1++ = fix_glyph (f, truncate, 0);
a2889657
JB
3893 }
3894 else if (mincol >= 0)
3895 {
3896 end = desired_glyphs->glyphs[vpos] + mincol;
3897 while (p1 < end)
3898 *p1++ = SPACEGLYPH;
3899 }
3900
3901 {
3902 register int len = p1 - desired_glyphs->glyphs[vpos];
3903
3904 if (len > desired_glyphs->used[vpos])
3905 desired_glyphs->used[vpos] = len;
3906 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
3907
3908 return len;
3909 }
3910}
3911\f
642eefc6
RS
3912/* This is like a combination of memq and assq.
3913 Return 1 if PROPVAL appears as an element of LIST
3914 or as the car of an element of LIST.
af460d46
RS
3915 If PROPVAL is a list, compare each element against LIST
3916 in that way, and return 1 if any element of PROPVAL is found in LIST.
642eefc6
RS
3917 Otherwise return 0.
3918 This function cannot quit. */
3919
3920int
3921invisible_p (propval, list)
3922 register Lisp_Object propval;
3923 Lisp_Object list;
3924{
af460d46
RS
3925 register Lisp_Object tail, proptail;
3926 for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
642eefc6
RS
3927 {
3928 register Lisp_Object tem;
af460d46 3929 tem = XCONS (tail)->car;
642eefc6
RS
3930 if (EQ (propval, tem))
3931 return 1;
3932 if (CONSP (tem) && EQ (propval, XCONS (tem)->car))
3933 return 1;
3934 }
af460d46
RS
3935 if (CONSP (propval))
3936 for (proptail = propval; CONSP (proptail);
3937 proptail = XCONS (proptail)->cdr)
3938 {
3939 Lisp_Object propelt;
3940 propelt = XCONS (proptail)->car;
3941 for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
3942 {
3943 register Lisp_Object tem;
3944 tem = XCONS (tail)->car;
3945 if (EQ (propelt, tem))
3946 return 1;
3947 if (CONSP (tem) && EQ (propelt, XCONS (tem)->car))
3948 return 1;
3949 }
3950 }
642eefc6
RS
3951 return 0;
3952}
3953
3954/* Return 1 if PROPVAL appears as the car of an element of LIST
3955 and the cdr of that element is non-nil.
af460d46
RS
3956 If PROPVAL is a list, check each element of PROPVAL in that way,
3957 and the first time some element is found,
3958 return 1 if the cdr of that element is non-nil.
642eefc6
RS
3959 Otherwise return 0.
3960 This function cannot quit. */
3961
3962int
3963invisible_ellipsis_p (propval, list)
3964 register Lisp_Object propval;
3965 Lisp_Object list;
3966{
af460d46
RS
3967 register Lisp_Object tail, proptail;
3968 for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
642eefc6
RS
3969 {
3970 register Lisp_Object tem;
af460d46 3971 tem = XCONS (tail)->car;
642eefc6
RS
3972 if (CONSP (tem) && EQ (propval, XCONS (tem)->car))
3973 return ! NILP (XCONS (tem)->cdr);
3974 }
af460d46
RS
3975 if (CONSP (propval))
3976 for (proptail = propval; CONSP (proptail);
3977 proptail = XCONS (proptail)->cdr)
3978 {
3979 Lisp_Object propelt;
3980 propelt = XCONS (proptail)->car;
3981 for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
3982 {
3983 register Lisp_Object tem;
3984 tem = XCONS (tail)->car;
3985 if (CONSP (tem) && EQ (propelt, XCONS (tem)->car))
3986 return ! NILP (XCONS (tem)->cdr);
3987 }
3988 }
642eefc6
RS
3989 return 0;
3990}
3991\f
a2889657
JB
3992void
3993syms_of_xdisp ()
3994{
cf074754
RS
3995 staticpro (&Qmenu_bar_update_hook);
3996 Qmenu_bar_update_hook = intern ("menu-bar-update-hook");
3997
a2889657
JB
3998 staticpro (&last_arrow_position);
3999 staticpro (&last_arrow_string);
4000 last_arrow_position = Qnil;
4001 last_arrow_string = Qnil;
4002
4003 DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
8c45d522 4004 "String (or mode line construct) included (normally) in `mode-line-format'.");
a2889657
JB
4005 Vglobal_mode_string = Qnil;
4006
4007 DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
4008 "Marker for where to display an arrow on top of the buffer text.\n\
4009This must be the beginning of a line in order to work.\n\
4010See also `overlay-arrow-string'.");
4011 Voverlay_arrow_position = Qnil;
4012
4013 DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
4014 "String to display as an arrow. See also `overlay-arrow-position'.");
4015 Voverlay_arrow_string = Qnil;
4016
4017 DEFVAR_INT ("scroll-step", &scroll_step,
4018 "*The number of lines to try scrolling a window by when point moves out.\n\
44fa5b1e
JB
4019If that fails to bring point back on frame, point is centered instead.\n\
4020If this is zero, point is always centered after it moves off frame.");
a2889657
JB
4021
4022 DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
4023
4024 DEFVAR_BOOL ("truncate-partial-width-windows",
4025 &truncate_partial_width_windows,
44fa5b1e 4026 "*Non-nil means truncate lines in all windows less than full frame wide.");
a2889657
JB
4027 truncate_partial_width_windows = 1;
4028
4029 DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
4030 "*Non-nil means use inverse video for the mode line.");
4031 mode_line_inverse_video = 1;
aa6d10fa
RS
4032
4033 DEFVAR_INT ("line-number-display-limit", &line_number_display_limit,
4034 "*Maximum buffer size for which line number should be displayed.");
4035 line_number_display_limit = 1000000;
fba9ce76
RS
4036
4037 DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
4038 "*Non-nil means highlight region even in nonselected windows.");
4039 highlight_nonselected_windows = 1;
d39b6696
KH
4040
4041 DEFVAR_BOOL ("multiple-frames", &multiple_frames,
3450d04c
KH
4042 "Non-nil if more than one frame is visible on this display.\n\
4043Minibuffer-only frames don't count, but iconified frames do.\n\
4044This variable is not guaranteed to be accurate except while parsing\n\
4045frame-title-format.");
d39b6696
KH
4046
4047 DEFVAR_LISP ("frame-title-format", &Vframe_title_format,
4048 "Template for displaying the titlebar of visible frames.\n\
4049\(Assuming the window manager supports this feature.)\n\
4050This variable has the same structure as `mode-line-format' (which see),\n\
4051and is used only on frames for which no explicit name has been set\n\
4052\(see `modify-frame-parameters').");
4053 DEFVAR_LISP ("icon-title-format", &Vicon_title_format,
4054 "Template for displaying the titlebar of an iconified frame.\n\
4055\(Assuming the window manager supports this feature.)\n\
4056This variable has the same structure as `mode-line-format' (which see),\n\
4057and is used only on frames for which no explicit name has been set\n\
4058\(see `modify-frame-parameters').");
4059 Vicon_title_format
4060 = Vframe_title_format
4061 = Fcons (intern ("multiple-frames"),
4062 Fcons (build_string ("%b"),
4063 Fcons (Fcons (build_string (""),
4064 Fcons (intern ("invocation-name"),
4065 Fcons (build_string ("@"),
4066 Fcons (intern ("system-name"),
4067 Qnil)))),
4068 Qnil)));
5992c4f7
KH
4069
4070 DEFVAR_LISP ("message-log-max", &Vmessage_log_max,
4071 "Maximum number of lines to keep in the message log buffer.\n\
4072If nil, disable message logging. If t, log messages but don't truncate\n\
4073the buffer when it becomes large.");
4074 XSETFASTINT (Vmessage_log_max, 50);
08b610e4
RS
4075
4076 DEFVAR_LISP ("window-size-change-functions", &Vwindow_size_change_functions,
4077 "Functions called before redisplay, if window sizes have changed.\n\
4078The value should be a list of functions that take one argument.\n\
4079Just before redisplay, for each frame, if any of its windows have changed\n\
4080size since the last redisplay, or have been split or deleted,\n\
4081all the functions in the list are called, with the frame as argument.");
4082 Vwindow_size_change_functions = Qnil;
a2889657
JB
4083}
4084
4085/* initialize the window system */
4086init_xdisp ()
4087{
4088 Lisp_Object root_window;
4089#ifndef COMPILER_REGISTER_BUG
4090 register
4091#endif /* COMPILER_REGISTER_BUG */
4092 struct window *mini_w;
4093
4094 this_line_bufpos = 0;
4095
4096 mini_w = XWINDOW (minibuf_window);
11e82b76 4097 root_window = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (mini_w)));
a2889657
JB
4098
4099 echo_area_glyphs = 0;
4100 previous_echo_glyphs = 0;
4101
4102 if (!noninteractive)
4103 {
44fa5b1e 4104 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (root_window)));
c2213350 4105 XSETFASTINT (XWINDOW (root_window)->top, 0);
44fa5b1e 4106 set_window_height (root_window, FRAME_HEIGHT (f) - 1, 0);
c2213350 4107 XSETFASTINT (mini_w->top, FRAME_HEIGHT (f) - 1);
a2889657
JB
4108 set_window_height (minibuf_window, 1, 0);
4109
c2213350
KH
4110 XSETFASTINT (XWINDOW (root_window)->width, FRAME_WIDTH (f));
4111 XSETFASTINT (mini_w->width, FRAME_WIDTH (f));
a2889657
JB
4112 }
4113}