]> code.delx.au - gnu-emacs/blob - src/xdisp.c
*** empty log message ***
[gnu-emacs] / src / xdisp.c
1 /* Display generation from window structure and buffer text.
2 Copyright (C) 1985, 1986, 1987, 1988, 1993 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21 #include "config.h"
22 #include <stdio.h>
23 /*#include <ctype.h>*/
24 #undef NULL
25 #include "lisp.h"
26 #include "frame.h"
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"
35 #include "termhooks.h"
36
37 extern int interrupt_input;
38 extern int command_loop_level;
39
40 /* Nonzero means print newline before next minibuffer message. */
41
42 int noninteractive_need_newline;
43
44 #define min(a, b) ((a) < (b) ? (a) : (b))
45 #define max(a, b) ((a) > (b) ? (a) : (b))
46
47 /* The buffer position of the first character appearing
48 entirely or partially on the current frame line.
49 Or zero, which disables the optimization for the current frame line. */
50 static int this_line_bufpos;
51
52 /* Number of characters past the end of this line,
53 including the terminating newline */
54 static int this_line_endpos;
55
56 /* The vertical position of this frame line. */
57 static int this_line_vpos;
58
59 /* Hpos value for start of display on this frame line.
60 Usually zero, but negative if first character really began
61 on previous line */
62 static int this_line_start_hpos;
63
64 /* Buffer that this_line variables are describing. */
65 static struct buffer *this_line_buffer;
66
67 /* Set by try_window_id to the vpos of first of any lines
68 scrolled on to the bottom of the frame. These lines should
69 not be included in any general scroll computation. */
70 static int scroll_bottom_vpos;
71
72 /* Value of echo_area_glyphs when it was last acted on.
73 If this is nonzero, there is a message on the frame
74 in the minibuffer and it should be erased as soon
75 as it is no longer requested to appear. */
76 char *previous_echo_glyphs;
77
78 /* Nonzero means truncate lines in all windows less wide than the frame */
79 int truncate_partial_width_windows;
80
81 Lisp_Object Vglobal_mode_string;
82
83 /* Marker for where to display an arrow on top of the buffer text. */
84 Lisp_Object Voverlay_arrow_position;
85
86 /* String to display for the arrow. */
87 Lisp_Object Voverlay_arrow_string;
88
89 /* Values of those variables at last redisplay. */
90 static Lisp_Object last_arrow_position, last_arrow_string;
91
92 /* Nonzero if overlay arrow has been displayed once in this window. */
93 static int overlay_arrow_seen;
94
95 /* Nonzero means highlight the region even in nonselected windows. */
96 static int highlight_nonselected_windows;
97
98 /* If cursor motion alone moves point off frame,
99 Try scrolling this many lines up or down if that will bring it back. */
100 int scroll_step;
101
102 /* Nonzero if try_window_id has made blank lines at window bottom
103 since the last redisplay that paused */
104 static int blank_end_of_window;
105
106 /* Number of windows showing the buffer of the selected window.
107 keyboard.c refers to this. */
108 int buffer_shared;
109
110 /* display_text_line sets these to the frame position (origin 0) of point,
111 whether the window is selected or not.
112 Set one to -1 first to determine whether point was found afterwards. */
113
114 static int cursor_vpos;
115 static int cursor_hpos;
116
117 int debug_end_pos;
118
119 /* Nonzero means display mode line highlighted */
120 int mode_line_inverse_video;
121
122 static void echo_area_display ();
123 void mark_window_display_accurate ();
124 static void redisplay_windows ();
125 static void redisplay_window ();
126 static void try_window ();
127 static int try_window_id ();
128 static struct position *display_text_line ();
129 static void display_mode_line ();
130 static int display_mode_element ();
131 static char *fmodetrunc ();
132 static char *decode_mode_spec ();
133 static int display_string ();
134 static void display_menu_bar ();
135 static int display_count_lines ();
136
137 /* Prompt to display in front of the minibuffer contents */
138 char *minibuf_prompt;
139
140 /* Width in columns of current minibuffer prompt. */
141 int minibuf_prompt_width;
142
143 /* Message to display instead of minibuffer contents
144 This is what the functions error and message make,
145 and command echoing uses it as well.
146 It overrides the minibuf_prompt as well as the buffer. */
147 char *echo_area_glyphs;
148
149 /* true iff we should redraw the mode lines on the next redisplay */
150 int update_mode_lines;
151
152 /* Smallest number of characters before the gap
153 at any time since last redisplay that finished.
154 Valid for current buffer when try_window_id can be called. */
155 int beg_unchanged;
156
157 /* Smallest number of characters after the gap
158 at any time since last redisplay that finished.
159 Valid for current buffer when try_window_id can be called. */
160 int end_unchanged;
161
162 /* MODIFF as of last redisplay that finished;
163 if it matches MODIFF, beg_unchanged and end_unchanged
164 contain no useful information */
165 int unchanged_modified;
166
167 /* Nonzero if head_clip or tail_clip of current buffer has changed
168 since last redisplay that finished */
169 int clip_changed;
170
171 /* Nonzero if window sizes or contents have changed
172 since last redisplay that finished */
173 int windows_or_buffers_changed;
174
175 /* Nonzero after display_mode_line if %l was used
176 and it displayed a line number. */
177 int line_number_displayed;
178
179 /* Maximum buffer size for which to display line numbers. */
180 int line_number_display_limit;
181 \f
182 /* Specify m, a string, as a message in the minibuf. If m is 0, clear out
183 any existing message, and let the minibuffer text show through. */
184 void
185 message1 (m)
186 char *m;
187 {
188 if (noninteractive)
189 {
190 if (noninteractive_need_newline)
191 putc ('\n', stderr);
192 noninteractive_need_newline = 0;
193 if (cursor_in_echo_area != 0)
194 fprintf (stderr, "%s", m);
195 else
196 fprintf (stderr, "%s\n", m);
197 fflush (stderr);
198 }
199 /* A null message buffer means that the frame hasn't really been
200 initialized yet. Error messages get reported properly by
201 cmd_error, so this must be just an informative message; toss it. */
202 else if (INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame))
203 {
204 #ifdef MULTI_FRAME
205 Lisp_Object minibuf_frame;
206
207 choose_minibuf_frame ();
208 minibuf_frame = WINDOW_FRAME (XWINDOW (minibuf_window));
209 FRAME_SAMPLE_VISIBILITY (XFRAME (minibuf_frame));
210 if (FRAME_VISIBLE_P (selected_frame)
211 && ! FRAME_VISIBLE_P (XFRAME (minibuf_frame)))
212 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (minibuf_window)));
213 #endif
214
215 if (m)
216 echo_area_glyphs = m;
217 else
218 echo_area_glyphs = previous_echo_glyphs = 0;
219
220 do_pending_window_change ();
221 echo_area_display ();
222 update_frame (XFRAME (XWINDOW (minibuf_window)->frame), 1, 1);
223 do_pending_window_change ();
224 }
225 }
226
227 /* Nonzero if FRAME_MESSAGE_BUF (selected_frame) is being used by print;
228 zero if being used by message. */
229 int message_buf_print;
230
231 /* Dump an informative message to the minibuf. If m is 0, clear out
232 any existing message, and let the minibuffer text show through. */
233 /* VARARGS 1 */
234 void
235 message (m, a1, a2, a3)
236 char *m;
237 {
238 if (noninteractive)
239 {
240 if (m)
241 {
242 if (noninteractive_need_newline)
243 putc ('\n', stderr);
244 noninteractive_need_newline = 0;
245 fprintf (stderr, m, a1, a2, a3);
246 if (cursor_in_echo_area == 0)
247 fprintf (stderr, "\n");
248 fflush (stderr);
249 }
250 }
251 else if (INTERACTIVE)
252 {
253 /* The frame whose minibuffer we're going to display the message on.
254 It may be larger than the selected frame, so we need
255 to use its buffer, not the selected frame's buffer. */
256 FRAME_PTR echo_frame;
257 #ifdef MULTI_FRAME
258 choose_minibuf_frame ();
259 echo_frame = XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
260 #else
261 echo_frame = selected_frame;
262 #endif
263
264 /* A null message buffer means that the frame hasn't really been
265 initialized yet. Error messages get reported properly by
266 cmd_error, so this must be just an informative message; toss it. */
267 if (FRAME_MESSAGE_BUF (echo_frame))
268 {
269 if (m)
270 {
271 {
272 #ifdef NO_ARG_ARRAY
273 int a[3];
274 a[0] = a1;
275 a[1] = a2;
276 a[2] = a3;
277
278 doprnt (FRAME_MESSAGE_BUF (echo_frame),
279 FRAME_WIDTH (echo_frame), m, 0, 3, a);
280 #else
281 doprnt (FRAME_MESSAGE_BUF (echo_frame),
282 FRAME_WIDTH (echo_frame), m, 0, 3, &a1);
283 #endif /* NO_ARG_ARRAY */
284 }
285
286 message1 (FRAME_MESSAGE_BUF (echo_frame));
287 }
288 else
289 message1 (0);
290
291 /* Print should start at the beginning of the message
292 buffer next time. */
293 message_buf_print = 0;
294 }
295 }
296 }
297
298 static void
299 echo_area_display ()
300 {
301 register int vpos;
302 FRAME_PTR f;
303
304 #ifdef MULTI_FRAME
305 choose_minibuf_frame ();
306 #endif
307
308 f = XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
309
310 if (! FRAME_VISIBLE_P (f))
311 return;
312
313 if (frame_garbaged)
314 {
315 redraw_garbaged_frames ();
316 frame_garbaged = 0;
317 }
318
319 if (echo_area_glyphs || minibuf_level == 0)
320 {
321 vpos = XFASTINT (XWINDOW (minibuf_window)->top);
322 get_display_line (f, vpos, 0);
323 display_string (XWINDOW (minibuf_window), vpos,
324 echo_area_glyphs ? echo_area_glyphs : "",
325 0, 0, 0, FRAME_WIDTH (f));
326
327 /* If desired cursor location is on this line, put it at end of text */
328 if (FRAME_CURSOR_Y (f) == vpos)
329 FRAME_CURSOR_X (f) = FRAME_DESIRED_GLYPHS (f)->used[vpos];
330
331 /* Fill the rest of the minibuffer window with blank lines. */
332 {
333 int i;
334
335 for (i = vpos + 1;
336 i < vpos + XFASTINT (XWINDOW (minibuf_window)->height); i++)
337 {
338 get_display_line (f, i, 0);
339 display_string (XWINDOW (minibuf_window), vpos,
340 "", 0, 0, 0, FRAME_WIDTH (f));
341 }
342 }
343 }
344 else if (!EQ (minibuf_window, selected_window))
345 windows_or_buffers_changed++;
346
347 if (EQ (minibuf_window, selected_window))
348 this_line_bufpos = 0;
349
350 previous_echo_glyphs = echo_area_glyphs;
351 }
352 \f
353 /* Do a frame update, taking possible shortcuts into account.
354 This is the main external entry point for redisplay.
355
356 If the last redisplay displayed an echo area message and that
357 message is no longer requested, we clear the echo area
358 or bring back the minibuffer if that is in use.
359
360 Everyone would like to have a hook here to call eval,
361 but that cannot be done safely without a lot of changes elsewhere.
362 This can be called from signal handlers; with alarms set up;
363 or with synchronous processes running.
364 See the function `echo' in keyboard.c.
365 See Fcall_process; if you called it from here, it could be
366 entered recursively. */
367
368 void
369 redisplay ()
370 {
371 register struct window *w = XWINDOW (selected_window);
372 register int pause;
373 int must_finish = 0;
374 int all_windows;
375 register int tlbufpos, tlendpos;
376 struct position pos;
377 extern int input_pending;
378
379 if (noninteractive)
380 return;
381
382 /* Set the visible flags for all frames.
383 Do this before checking for resized or garbaged frames; they want
384 to know if their frames are visible.
385 See the comment in frame.h for FRAME_SAMPLE_VISIBILITY. */
386 {
387 Lisp_Object tail, frame;
388
389 FOR_EACH_FRAME (tail, frame)
390 FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
391 }
392
393 /* Notice any pending interrupt request to change frame size. */
394 do_pending_window_change ();
395
396 if (frame_garbaged)
397 {
398 redraw_garbaged_frames ();
399 frame_garbaged = 0;
400 }
401
402 /* Normally the message* functions will have already displayed and
403 updated the echo area, but the frame may have been trashed, or
404 the update may have been preempted, so display the echo area
405 again here. */
406 if (echo_area_glyphs || previous_echo_glyphs)
407 {
408 echo_area_display ();
409 must_finish = 1;
410 }
411
412 if (clip_changed || windows_or_buffers_changed)
413 update_mode_lines++;
414
415 /* Detect case that we need to write a star in the mode line. */
416 if (XFASTINT (w->last_modified) < MODIFF
417 && XFASTINT (w->last_modified) <= current_buffer->save_modified)
418 {
419 w->update_mode_line = Qt;
420 if (buffer_shared > 1)
421 update_mode_lines++;
422 }
423
424 FRAME_SCROLL_BOTTOM_VPOS (XFRAME (w->frame)) = -1;
425
426 all_windows = update_mode_lines || buffer_shared > 1;
427
428 /* If specs for an arrow have changed, do thorough redisplay
429 to ensure we remove any arrow that should no longer exist. */
430 if (! EQ (Voverlay_arrow_position, last_arrow_position)
431 || ! EQ (Voverlay_arrow_string, last_arrow_string))
432 all_windows = 1, clip_changed = 1;
433
434 /* If showing region, and mark has changed, must redisplay whole window. */
435 if (((!NILP (Vtransient_mark_mode)
436 && !NILP (XBUFFER (w->buffer)->mark_active))
437 != !NILP (w->region_showing))
438 || (!NILP (w->region_showing)
439 && !EQ (w->region_showing,
440 Fmarker_position (XBUFFER (w->buffer)->mark))))
441 this_line_bufpos = -1;
442
443 tlbufpos = this_line_bufpos;
444 tlendpos = this_line_endpos;
445 if (!all_windows && tlbufpos > 0 && NILP (w->update_mode_line)
446 && FRAME_VISIBLE_P (XFRAME (w->frame))
447 /* Make sure recorded data applies to current buffer, etc */
448 && this_line_buffer == current_buffer
449 && current_buffer == XBUFFER (w->buffer)
450 && NILP (w->force_start)
451 /* Point must be on the line that we have info recorded about */
452 && point >= tlbufpos
453 && point <= Z - tlendpos
454 /* All text outside that line, including its final newline,
455 must be unchanged */
456 && (XFASTINT (w->last_modified) >= MODIFF
457 || (beg_unchanged >= tlbufpos - 1
458 && GPT >= tlbufpos
459 /* If selective display, can't optimize
460 if the changes start at the beginning of the line. */
461 && ((XTYPE (current_buffer->selective_display) == Lisp_Int
462 && XINT (current_buffer->selective_display) > 0
463 ? (beg_unchanged >= tlbufpos
464 && GPT > tlbufpos)
465 : 1))
466 && end_unchanged >= tlendpos
467 && Z - GPT >= tlendpos)))
468 {
469 if (tlbufpos > BEGV && FETCH_CHAR (tlbufpos - 1) != '\n'
470 && (tlbufpos == ZV
471 || FETCH_CHAR (tlbufpos) == '\n'))
472 /* Former continuation line has disappeared by becoming empty */
473 goto cancel;
474 else if (XFASTINT (w->last_modified) < MODIFF
475 || MINI_WINDOW_P (w))
476 {
477 cursor_vpos = -1;
478 overlay_arrow_seen = 0;
479 display_text_line (w, tlbufpos, this_line_vpos, this_line_start_hpos,
480 pos_tab_offset (w, tlbufpos));
481 /* If line contains point, is not continued,
482 and ends at same distance from eob as before, we win */
483 if (cursor_vpos >= 0 && this_line_bufpos
484 && this_line_endpos == tlendpos)
485 {
486 if (XFASTINT (w->width) != FRAME_WIDTH (XFRAME (WINDOW_FRAME (w))))
487 preserve_other_columns (w);
488 goto update;
489 }
490 else
491 goto cancel;
492 }
493 else if (point == XFASTINT (w->last_point))
494 {
495 if (!must_finish)
496 {
497 do_pending_window_change ();
498 return;
499 }
500 goto update;
501 }
502 /* If highlighting the region, we can't just move the cursor. */
503 else if (! (!NILP (Vtransient_mark_mode)
504 && !NILP (current_buffer->mark_active))
505 && NILP (w->region_showing))
506 {
507 pos = *compute_motion (tlbufpos, 0,
508 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
509 point, 2, - (1 << (SHORTBITS - 1)),
510 window_internal_width (w) - 1,
511 XINT (w->hscroll),
512 pos_tab_offset (w, tlbufpos));
513 if (pos.vpos < 1)
514 {
515 FRAME_CURSOR_X (selected_frame)
516 = XFASTINT (w->left) + max (pos.hpos, 0);
517 FRAME_CURSOR_Y (selected_frame) = this_line_vpos;
518 goto update;
519 }
520 else
521 goto cancel;
522 }
523 cancel:
524 /* Text changed drastically or point moved off of line */
525 cancel_line (this_line_vpos, selected_frame);
526 }
527
528 this_line_bufpos = 0;
529 all_windows |= buffer_shared > 1;
530
531 if (all_windows)
532 {
533 Lisp_Object tail, frame;
534
535 #ifdef HAVE_X_WINDOWS
536 /* Since we're doing a thorough redisplay, we might as well
537 recompute all our display faces. */
538 clear_face_vector ();
539 #endif
540
541 /* Recompute # windows showing selected buffer.
542 This will be incremented each time such a window is displayed. */
543 buffer_shared = 0;
544
545 FOR_EACH_FRAME (tail, frame)
546 {
547 FRAME_PTR f = XFRAME (frame);
548
549 /* Mark all the scroll bars to be removed; we'll redeem the ones
550 we want when we redisplay their windows. */
551 if (condemn_scroll_bars_hook)
552 (*condemn_scroll_bars_hook) (f);
553
554 if (FRAME_VISIBLE_P (f))
555 redisplay_windows (FRAME_ROOT_WINDOW (f));
556
557 /* Any scroll bars which redisplay_windows should have nuked
558 should now go away. */
559 if (judge_scroll_bars_hook)
560 (*judge_scroll_bars_hook) (f);
561 }
562 }
563 else if (FRAME_VISIBLE_P (selected_frame))
564 {
565 redisplay_window (selected_window, 1);
566 if (XFASTINT (w->width) != FRAME_WIDTH (selected_frame))
567 preserve_other_columns (w);
568 }
569
570 update:
571 /* Prevent various kinds of signals during display update.
572 stdio is not robust about handling signals,
573 which can cause an apparent I/O error. */
574 if (interrupt_input)
575 unrequest_sigio ();
576 stop_polling ();
577
578 #ifdef MULTI_FRAME
579 if (all_windows)
580 {
581 Lisp_Object tail;
582
583 pause = 0;
584
585 for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
586 {
587 FRAME_PTR f;
588
589 if (XTYPE (XCONS (tail)->car) != Lisp_Frame)
590 continue;
591
592 f = XFRAME (XCONS (tail)->car);
593 if (FRAME_VISIBLE_P (f))
594 {
595 pause |= update_frame (f, 0, 0);
596 if (!pause)
597 mark_window_display_accurate (f->root_window, 1);
598 }
599 }
600 }
601 else
602 #endif /* MULTI_FRAME */
603 {
604 if (FRAME_VISIBLE_P (selected_frame))
605 pause = update_frame (selected_frame, 0, 0);
606
607 /* We may have called echo_area_display at the top of this
608 function. If the echo area is on another frame, that may
609 have put text on a frame other than the selected one, so the
610 above call to update_frame would not have caught it. Catch
611 it here. */
612 {
613 FRAME_PTR mini_frame =
614 XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
615
616 if (mini_frame != selected_frame)
617 pause |= update_frame (mini_frame, 0, 0);
618 }
619 }
620
621 /* If frame does not match, prevent doing single-line-update next time.
622 Also, don't forget to check every line to update the arrow. */
623 if (pause)
624 {
625 this_line_bufpos = 0;
626 if (!NILP (last_arrow_position))
627 {
628 last_arrow_position = Qt;
629 last_arrow_string = Qt;
630 }
631 /* If we pause after scrolling, some lines in current_frame
632 may be null, so preserve_other_columns won't be able to
633 preserve all the vertical-bar separators. So, avoid using it
634 in that case. */
635 if (XFASTINT (w->width) != FRAME_WIDTH (selected_frame))
636 update_mode_lines = 1;
637 }
638
639 /* Now text on frame agrees with windows, so
640 put info into the windows for partial redisplay to follow */
641
642 if (!pause)
643 {
644 register struct buffer *b = XBUFFER (w->buffer);
645
646 blank_end_of_window = 0;
647 clip_changed = 0;
648 unchanged_modified = BUF_MODIFF (b);
649 beg_unchanged = BUF_GPT (b) - BUF_BEG (b);
650 end_unchanged = BUF_Z (b) - BUF_GPT (b);
651
652 XFASTINT (w->last_point) = BUF_PT (b);
653 XFASTINT (w->last_point_x) = FRAME_CURSOR_X (selected_frame);
654 XFASTINT (w->last_point_y) = FRAME_CURSOR_Y (selected_frame);
655
656 if (all_windows)
657 mark_window_display_accurate (FRAME_ROOT_WINDOW (selected_frame), 1);
658 else
659 {
660 w->update_mode_line = Qnil;
661 XFASTINT (w->last_modified) = BUF_MODIFF (b);
662 w->window_end_valid = Qt;
663 last_arrow_position = Voverlay_arrow_position;
664 last_arrow_string = Voverlay_arrow_string;
665 }
666 update_mode_lines = 0;
667 windows_or_buffers_changed = 0;
668 }
669
670 /* Start SIGIO interrupts coming again.
671 Having them off during the code above
672 makes it less likely one will discard output,
673 but not impossible, since there might be stuff
674 in the system buffer here.
675 But it is much hairier to try to do anything about that. */
676
677 if (interrupt_input)
678 request_sigio ();
679 start_polling ();
680
681 /* Change frame size now if a change is pending. */
682 do_pending_window_change ();
683 }
684
685 /* Redisplay, but leave alone any recent echo area message
686 unless another message has been requested in its place.
687
688 This is useful in situations where you need to redisplay but no
689 user action has occurred, making it inappropriate for the message
690 area to be cleared. See tracking_off and
691 wait_reading_process_input for examples of these situations. */
692
693 redisplay_preserve_echo_area ()
694 {
695 if (echo_area_glyphs == 0 && previous_echo_glyphs != 0)
696 {
697 echo_area_glyphs = previous_echo_glyphs;
698 redisplay ();
699 echo_area_glyphs = 0;
700 }
701 else
702 redisplay ();
703 }
704
705 void
706 mark_window_display_accurate (window, flag)
707 Lisp_Object window;
708 int flag;
709 {
710 register struct window *w;
711
712 for (;!NILP (window); window = w->next)
713 {
714 if (XTYPE (window) != Lisp_Window) abort ();
715 w = XWINDOW (window);
716
717 if (!NILP (w->buffer))
718 {
719 XFASTINT (w->last_modified)
720 = !flag ? 0
721 : XBUFFER (w->buffer) == current_buffer
722 ? MODIFF : BUF_MODIFF (XBUFFER (w->buffer));
723
724 /* Record if we are showing a region, so can make sure to
725 update it fully at next redisplay. */
726 w->region_showing = (!NILP (Vtransient_mark_mode)
727 && !NILP (XBUFFER (w->buffer)->mark_active)
728 ? Fmarker_position (XBUFFER (w->buffer)->mark)
729 : Qnil);
730 }
731
732 w->window_end_valid = Qt;
733 w->update_mode_line = Qnil;
734
735 if (!NILP (w->vchild))
736 mark_window_display_accurate (w->vchild, flag);
737 if (!NILP (w->hchild))
738 mark_window_display_accurate (w->hchild, flag);
739 }
740
741 if (flag)
742 {
743 last_arrow_position = Voverlay_arrow_position;
744 last_arrow_string = Voverlay_arrow_string;
745 }
746 else
747 {
748 /* t is unequal to any useful value of Voverlay_arrow_... */
749 last_arrow_position = Qt;
750 last_arrow_string = Qt;
751 }
752 }
753 \f
754 int do_id = 1;
755
756 static void
757 redisplay_windows (window)
758 Lisp_Object window;
759 {
760 for (; !NILP (window); window = XWINDOW (window)->next)
761 redisplay_window (window, 0);
762 }
763
764 static void
765 redisplay_window (window, just_this_one)
766 Lisp_Object window;
767 int just_this_one;
768 {
769 register struct window *w = XWINDOW (window);
770 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
771 int height;
772 register int lpoint = point;
773 struct buffer *old = current_buffer;
774 register int width = window_internal_width (w) - 1;
775 register int startp;
776 register int hscroll = XINT (w->hscroll);
777 struct position pos;
778 int opoint = point;
779 int tem;
780 int window_needs_modeline;
781
782 if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
783
784 /* If this is a combination window, do its children; that's all. */
785
786 if (!NILP (w->vchild))
787 {
788 redisplay_windows (w->vchild);
789 return;
790 }
791 if (!NILP (w->hchild))
792 {
793 redisplay_windows (w->hchild);
794 return;
795 }
796 if (NILP (w->buffer))
797 abort ();
798
799 height = window_internal_height (w);
800
801 if (MINI_WINDOW_P (w))
802 {
803 if (w == XWINDOW (minibuf_window))
804 {
805 if (echo_area_glyphs)
806 /* We've already displayed the echo area glyphs, if any. */
807 goto finish_scroll_bars;
808 }
809 else
810 {
811 /* This is a minibuffer, but it's not the currently active one, so
812 clear it. */
813 int vpos = XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top);
814 int i;
815
816 for (i = 0; i < height; i++)
817 {
818 get_display_line (f, vpos + i, 0);
819 display_string (w, vpos + i, "", 0, 0, 0, width);
820 }
821
822 goto finish_scroll_bars;
823 }
824 }
825
826 if (update_mode_lines)
827 w->update_mode_line = Qt;
828
829 /* Otherwise set up data on this window; select its buffer and point value */
830
831 current_buffer = XBUFFER (w->buffer);
832 opoint = point;
833
834 /* Count number of windows showing the selected buffer. */
835
836 if (!just_this_one
837 && current_buffer == XBUFFER (XWINDOW (selected_window)->buffer))
838 buffer_shared++;
839
840 /* POINT refers normally to the selected window.
841 For any other window, set up appropriate value. */
842
843 if (!EQ (window, selected_window))
844 {
845 SET_PT (marker_position (w->pointm));
846 if (point < BEGV)
847 {
848 SET_PT (BEGV);
849 Fset_marker (w->pointm, make_number (point), Qnil);
850 }
851 else if (point > (ZV - 1))
852 {
853 SET_PT (ZV);
854 Fset_marker (w->pointm, make_number (point), Qnil);
855 }
856 }
857
858 /* If window-start is screwed up, choose a new one. */
859 if (XMARKER (w->start)->buffer != current_buffer)
860 goto recenter;
861
862 startp = marker_position (w->start);
863
864 /* Handle case where place to start displaying has been specified,
865 unless the specified location is outside the accessible range. */
866 if (!NILP (w->force_start))
867 {
868 /* Forget any recorded base line for line number display. */
869 w->base_line_number = Qnil;
870 w->update_mode_line = Qt;
871 w->force_start = Qnil;
872 XFASTINT (w->last_modified) = 0;
873 if (startp < BEGV) startp = BEGV;
874 if (startp > ZV) startp = ZV;
875 try_window (window, startp);
876 if (cursor_vpos < 0)
877 {
878 /* ??? What should happen here if highlighting a region? */
879 /* If point does not appear, move point so it does appear */
880 pos = *compute_motion (startp, 0,
881 ((EQ (window, minibuf_window) && startp == 1)
882 ? minibuf_prompt_width : 0)
883 +
884 (hscroll ? 1 - hscroll : 0),
885 ZV, height / 2,
886 - (1 << (SHORTBITS - 1)),
887 width, hscroll, pos_tab_offset (w, startp));
888 SET_PT (pos.bufpos);
889 if (w != XWINDOW (FRAME_SELECTED_WINDOW (f)))
890 Fset_marker (w->pointm, make_number (point), Qnil);
891 else
892 {
893 lpoint = point;
894 FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left);
895 FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
896 }
897 }
898 goto done;
899 }
900
901 /* Handle case where text has not changed, only point,
902 and it has not moved off the frame */
903
904 /* This code is not used for minibuffer for the sake of
905 the case of redisplaying to replace an echo area message;
906 since in that case the minibuffer contents per se are usually unchanged.
907 This code is of no real use in the minibuffer since
908 the handling of this_line_bufpos, etc.,
909 in redisplay handles the same cases. */
910
911 if (XFASTINT (w->last_modified) >= MODIFF
912 && point >= startp && !clip_changed
913 && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
914 /* Can't use this case if highlighting a region. */
915 && !(!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
916 && NILP (w->region_showing)
917 && !EQ (window, minibuf_window))
918 {
919 pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
920 point, height + 1, 10000, width, hscroll,
921 pos_tab_offset (w, startp));
922
923 if (pos.vpos < height)
924 {
925 /* Ok, point is still on frame */
926 if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
927 {
928 /* These variables are supposed to be origin 1 */
929 FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left);
930 FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
931 }
932 /* This doesn't do the trick, because if a window to the right of
933 this one must be redisplayed, this does nothing because there
934 is nothing in DesiredFrame yet, and then the other window is
935 redisplayed, making likes that are empty in this window's columns.
936 if (XFASTINT (w->width) != FRAME_WIDTH (f))
937 preserve_my_columns (w);
938 */
939 goto done;
940 }
941 /* Don't bother trying redisplay with same start;
942 we already know it will lose */
943 }
944 /* If current starting point was originally the beginning of a line
945 but no longer is, find a new starting point. */
946 else if (!NILP (w->start_at_line_beg)
947 && !(startp == BEGV
948 || FETCH_CHAR (startp - 1) == '\n'))
949 {
950 goto recenter;
951 }
952 else if (just_this_one && !MINI_WINDOW_P (w)
953 && point >= startp
954 && XFASTINT (w->last_modified)
955 /* or else vmotion on first line won't work. */
956 && ! NILP (w->start_at_line_beg)
957 && ! EQ (w->window_end_valid, Qnil)
958 && do_id && !clip_changed
959 && !blank_end_of_window
960 && XFASTINT (w->width) == FRAME_WIDTH (f)
961 /* Can't use this case if highlighting a region. */
962 && !(!NILP (Vtransient_mark_mode)
963 && !NILP (current_buffer->mark_active))
964 && NILP (w->region_showing)
965 && EQ (last_arrow_position, Voverlay_arrow_position)
966 && EQ (last_arrow_string, Voverlay_arrow_string)
967 && (tem = try_window_id (FRAME_SELECTED_WINDOW (f)))
968 && tem != -2)
969 {
970 /* tem > 0 means success. tem == -1 means choose new start.
971 tem == -2 means try again with same start,
972 and nothing but whitespace follows the changed stuff.
973 tem == 0 means try again with same start. */
974 if (tem > 0)
975 goto done;
976 }
977 else if (startp >= BEGV && startp <= ZV
978 /* Avoid starting display at end of buffer! */
979 && (startp < ZV || startp == BEGV
980 || (XFASTINT (w->last_modified) >= MODIFF)))
981 {
982 /* Try to redisplay starting at same place as before */
983 /* If point has not moved off frame, accept the results */
984 try_window (window, startp);
985 if (cursor_vpos >= 0)
986 {
987 if (!just_this_one || clip_changed || beg_unchanged < startp)
988 /* Forget any recorded base line for line number display. */
989 w->base_line_number = Qnil;
990 goto done;
991 }
992 else
993 cancel_my_columns (w);
994 }
995
996 XFASTINT (w->last_modified) = 0;
997 w->update_mode_line = Qt;
998
999 /* Try to scroll by specified few lines */
1000
1001 if (scroll_step && !clip_changed)
1002 {
1003 if (point > startp)
1004 {
1005 pos = *vmotion (Z - XFASTINT (w->window_end_pos),
1006 scroll_step, width, hscroll, window);
1007 if (pos.vpos >= height)
1008 goto scroll_fail;
1009 }
1010
1011 pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step,
1012 width, hscroll, window);
1013
1014 if (point >= pos.bufpos)
1015 {
1016 try_window (window, pos.bufpos);
1017 if (cursor_vpos >= 0)
1018 {
1019 if (!just_this_one || clip_changed || beg_unchanged < startp)
1020 /* Forget any recorded base line for line number display. */
1021 w->base_line_number = Qnil;
1022 goto done;
1023 }
1024 else
1025 cancel_my_columns (w);
1026 }
1027 scroll_fail: ;
1028 }
1029
1030 /* Finally, just choose place to start which centers point */
1031
1032 recenter:
1033 /* Forget any previously recorded base line for line number display. */
1034 w->base_line_number = Qnil;
1035
1036 pos = *vmotion (point, - height / 2, width, hscroll, window);
1037 try_window (window, pos.bufpos);
1038
1039 startp = marker_position (w->start);
1040 w->start_at_line_beg =
1041 (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
1042
1043 done:
1044 if ((!NILP (w->update_mode_line)
1045 /* If window not full width, must redo its mode line
1046 if the window to its side is being redone */
1047 || (!just_this_one && width < FRAME_WIDTH (f) - 1)
1048 || INTEGERP (w->base_line_pos))
1049 && height != XFASTINT (w->height))
1050 display_mode_line (w);
1051 if (! line_number_displayed
1052 && ! BUFFERP (w->base_line_pos))
1053 {
1054 w->base_line_pos = Qnil;
1055 w->base_line_number = Qnil;
1056 }
1057
1058 /* When we reach a frame's selected window, redo the frame's menu bar. */
1059 if (!NILP (w->update_mode_line)
1060 && FRAME_MENU_BAR_LINES (f) > 0
1061 && EQ (FRAME_SELECTED_WINDOW (f), window))
1062 display_menu_bar (w);
1063
1064 finish_scroll_bars:
1065 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
1066 {
1067 int start, end, whole;
1068
1069 /* Calculate the start and end positions for the current window.
1070 At some point, it would be nice to choose between scrollbars
1071 which reflect the whole buffer size, with special markers
1072 indicating narrowing, and scrollbars which reflect only the
1073 visible region.
1074
1075 Note that minibuffers sometimes aren't displaying any text. */
1076 if (! MINI_WINDOW_P (w)
1077 || (w == XWINDOW (minibuf_window) && ! echo_area_glyphs))
1078 {
1079 whole = ZV - BEGV;
1080 start = startp - BEGV;
1081 /* I don't think this is guaranteed to be right. For the
1082 moment, we'll pretend it is. */
1083 end = (Z - XINT (w->window_end_pos)) - BEGV;
1084
1085 if (end < start) end = start;
1086 if (whole < (end - start)) whole = end - start;
1087 }
1088 else
1089 start = end = whole = 0;
1090
1091 /* Indicate what this scroll bar ought to be displaying now. */
1092 (*set_vertical_scroll_bar_hook) (w, end - start, whole, start);
1093
1094 /* Note that we actually used the scroll bar attached to this window,
1095 so it shouldn't be deleted at the end of redisplay. */
1096 (*redeem_scroll_bar_hook) (w);
1097 }
1098
1099 SET_PT (opoint);
1100 current_buffer = old;
1101 SET_PT (lpoint);
1102 }
1103 \f
1104 /* Do full redisplay on one window, starting at position `pos'. */
1105
1106 static void
1107 try_window (window, pos)
1108 Lisp_Object window;
1109 register int pos;
1110 {
1111 register struct window *w = XWINDOW (window);
1112 register int height = window_internal_height (w);
1113 register int vpos = XFASTINT (w->top);
1114 register int last_text_vpos = vpos;
1115 int tab_offset = pos_tab_offset (w, pos);
1116 FRAME_PTR f = XFRAME (w->frame);
1117 int width = window_internal_width (w) - 1;
1118 struct position val;
1119
1120 Fset_marker (w->start, make_number (pos), Qnil);
1121 cursor_vpos = -1;
1122 overlay_arrow_seen = 0;
1123 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
1124
1125 while (--height >= 0)
1126 {
1127 val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
1128 tab_offset += width;
1129 if (val.vpos) tab_offset = 0;
1130 vpos++;
1131 if (pos != val.bufpos)
1132 last_text_vpos
1133 /* Next line, unless prev line ended in end of buffer with no cr */
1134 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
1135 pos = val.bufpos;
1136 }
1137
1138 /* If last line is continued in middle of character,
1139 include the split character in the text considered on the frame */
1140 if (val.hpos < (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
1141 pos++;
1142
1143 /* If bottom just moved off end of frame, change mode line percentage. */
1144 if (XFASTINT (w->window_end_pos) == 0
1145 && Z != pos)
1146 w->update_mode_line = Qt;
1147
1148 /* Say where last char on frame will be, once redisplay is finished. */
1149 XFASTINT (w->window_end_pos) = Z - pos;
1150 XFASTINT (w->window_end_vpos) = last_text_vpos - XFASTINT (w->top);
1151 /* But that is not valid info until redisplay finishes. */
1152 w->window_end_valid = Qnil;
1153 }
1154 \f
1155 /* Try to redisplay when buffer is modified locally,
1156 computing insert/delete line to preserve text outside
1157 the bounds of the changes.
1158 Return 1 if successful, 0 if if cannot tell what to do,
1159 or -1 to tell caller to find a new window start,
1160 or -2 to tell caller to do normal redisplay with same window start. */
1161
1162 static int
1163 try_window_id (window)
1164 Lisp_Object window;
1165 {
1166 int pos;
1167 register struct window *w = XWINDOW (window);
1168 register int height = window_internal_height (w);
1169 FRAME_PTR f = XFRAME (w->frame);
1170 int top = XFASTINT (w->top);
1171 int start = marker_position (w->start);
1172 int width = window_internal_width (w) - 1;
1173 int hscroll = XINT (w->hscroll);
1174 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
1175 register int vpos;
1176 register int i, tem;
1177 int last_text_vpos = 0;
1178 int stop_vpos;
1179
1180 struct position val, bp, ep, xp, pp;
1181 int scroll_amount = 0;
1182 int delta;
1183 int tab_offset, epto;
1184
1185 if (GPT - BEG < beg_unchanged)
1186 beg_unchanged = GPT - BEG;
1187 if (Z - GPT < end_unchanged)
1188 end_unchanged = Z - GPT;
1189
1190 if (beg_unchanged + 1 < start)
1191 return 0; /* Give up if changes go above top of window */
1192
1193 /* Find position before which nothing is changed. */
1194 bp = *compute_motion (start, 0, lmargin,
1195 beg_unchanged + 1, height + 1, 0, width, hscroll,
1196 pos_tab_offset (w, start));
1197 if (bp.vpos >= height)
1198 {
1199 if (point < bp.bufpos && !bp.contin)
1200 {
1201 /* All changes are below the frame, and point is on the frame.
1202 We don't need to change the frame at all.
1203 But we need to update window_end_pos to account for
1204 any change in buffer size. */
1205 bp = *compute_motion (start, 0, lmargin,
1206 Z, height, 0,
1207 width, hscroll, pos_tab_offset (w, start));
1208 XFASTINT (w->window_end_vpos) = height;
1209 XFASTINT (w->window_end_pos) = Z - bp.bufpos;
1210 return 1;
1211 }
1212 return 0;
1213 }
1214
1215 vpos = bp.vpos;
1216
1217 /* Find beginning of that frame line. Must display from there. */
1218 bp = *vmotion (bp.bufpos, 0, width, hscroll, window);
1219
1220 pos = bp.bufpos;
1221 val.hpos = lmargin;
1222 if (pos < start)
1223 return -1;
1224
1225 /* If about to start displaying at the beginning of a continuation line,
1226 really start with previous frame line, in case it was not
1227 continued when last redisplayed */
1228 if ((bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0)
1229 ||
1230 /* Likewise if we have to worry about selective display. */
1231 (XTYPE (current_buffer->selective_display) == Lisp_Int
1232 && XINT (current_buffer->selective_display) > 0
1233 && bp.bufpos - 1 == beg_unchanged && vpos > 0))
1234 {
1235 bp = *vmotion (bp.bufpos, -1, width, hscroll, window);
1236 --vpos;
1237 pos = bp.bufpos;
1238 }
1239
1240 if (bp.contin && bp.hpos != lmargin)
1241 {
1242 val.hpos = bp.prevhpos - width + lmargin;
1243 pos--;
1244 }
1245
1246 bp.vpos = vpos;
1247
1248 /* Find first visible newline after which no more is changed. */
1249 tem = find_next_newline (Z - max (end_unchanged, Z - ZV), 1);
1250 if (XTYPE (current_buffer->selective_display) == Lisp_Int
1251 && XINT (current_buffer->selective_display) > 0)
1252 while (tem < ZV - 1
1253 && (position_indentation (tem)
1254 >= XINT (current_buffer->selective_display)))
1255 tem = find_next_newline (tem, 1);
1256
1257 /* Compute the cursor position after that newline. */
1258 ep = *compute_motion (pos, vpos, val.hpos, tem,
1259 height, - (1 << (SHORTBITS - 1)),
1260 width, hscroll, pos_tab_offset (w, bp.bufpos));
1261
1262 /* If changes reach past the text available on the frame,
1263 just display rest of frame. */
1264 if (ep.bufpos > Z - XFASTINT (w->window_end_pos))
1265 stop_vpos = height;
1266 else
1267 stop_vpos = ep.vpos;
1268
1269 /* If no newline before ep, the line ep is on includes some changes
1270 that must be displayed. Make sure we don't stop before it. */
1271 /* Also, if changes reach all the way until ep.bufpos,
1272 it is possible that something was deleted after the
1273 newline before it, so the following line must be redrawn. */
1274 if (stop_vpos == ep.vpos
1275 && (ep.bufpos == BEGV
1276 || FETCH_CHAR (ep.bufpos - 1) != '\n'
1277 || ep.bufpos == Z - end_unchanged))
1278 stop_vpos = ep.vpos + 1;
1279
1280 cursor_vpos = -1;
1281 overlay_arrow_seen = 0;
1282
1283 /* If changes do not reach to bottom of window,
1284 figure out how much to scroll the rest of the window */
1285 if (stop_vpos < height)
1286 {
1287 /* Now determine how far up or down the rest of the window has moved */
1288 epto = pos_tab_offset (w, ep.bufpos);
1289 xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
1290 Z - XFASTINT (w->window_end_pos),
1291 10000, 0, width, hscroll, epto);
1292 scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
1293
1294 /* Is everything on frame below the changes whitespace?
1295 If so, no scrolling is really necessary. */
1296 for (i = ep.bufpos; i < xp.bufpos; i++)
1297 {
1298 tem = FETCH_CHAR (i);
1299 if (tem != ' ' && tem != '\n' && tem != '\t')
1300 break;
1301 }
1302 if (i == xp.bufpos)
1303 return -2;
1304
1305 XFASTINT (w->window_end_vpos) += scroll_amount;
1306
1307 /* Before doing any scrolling, verify that point will be on frame. */
1308 if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height))
1309 {
1310 if (point <= xp.bufpos)
1311 {
1312 pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
1313 point, height, - (1 << (SHORTBITS - 1)),
1314 width, hscroll, epto);
1315 }
1316 else
1317 {
1318 pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
1319 point, height, - (1 << (SHORTBITS - 1)),
1320 width, hscroll, pos_tab_offset (w, xp.bufpos));
1321 }
1322 if (pp.bufpos < point || pp.vpos == height)
1323 return 0;
1324 cursor_vpos = pp.vpos + top;
1325 cursor_hpos = pp.hpos + XFASTINT (w->left);
1326 }
1327
1328 if (stop_vpos - scroll_amount >= height
1329 || ep.bufpos == xp.bufpos)
1330 {
1331 if (scroll_amount < 0)
1332 stop_vpos -= scroll_amount;
1333 scroll_amount = 0;
1334 /* In this path, we have altered window_end_vpos
1335 and not left it negative.
1336 We must make sure that, in case display is preempted
1337 before the frame changes to reflect what we do here,
1338 further updates will not come to try_window_id
1339 and assume the frame and window_end_vpos match. */
1340 blank_end_of_window = 1;
1341 }
1342 else if (!scroll_amount)
1343 {}
1344 else if (bp.bufpos == Z - end_unchanged)
1345 {
1346 /* If reprinting everything is nearly as fast as scrolling,
1347 don't bother scrolling. Can happen if lines are short. */
1348 if (scroll_cost (f, bp.vpos + top - scroll_amount,
1349 top + height - max (0, scroll_amount),
1350 scroll_amount)
1351 > xp.bufpos - bp.bufpos - 20)
1352 /* Return "try normal display with same window-start."
1353 Too bad we can't prevent further scroll-thinking. */
1354 return -2;
1355 /* If pure deletion, scroll up as many lines as possible.
1356 In common case of killing a line, this can save the
1357 following line from being overwritten by scrolling
1358 and therefore having to be redrawn. */
1359 tem = scroll_frame_lines (f, bp.vpos + top - scroll_amount,
1360 top + height - max (0, scroll_amount),
1361 scroll_amount);
1362 if (!tem) stop_vpos = height;
1363 }
1364 else if (scroll_amount)
1365 {
1366 /* If reprinting everything is nearly as fast as scrolling,
1367 don't bother scrolling. Can happen if lines are short. */
1368 /* Note that if scroll_amount > 0, xp.bufpos - bp.bufpos is an
1369 overestimate of cost of reprinting, since xp.bufpos
1370 would end up below the bottom of the window. */
1371 if (scroll_cost (f, ep.vpos + top - scroll_amount,
1372 top + height - max (0, scroll_amount),
1373 scroll_amount)
1374 > xp.bufpos - ep.bufpos - 20)
1375 /* Return "try normal display with same window-start."
1376 Too bad we can't prevent further scroll-thinking. */
1377 return -2;
1378 tem = scroll_frame_lines (f, ep.vpos + top - scroll_amount,
1379 top + height - max (0, scroll_amount),
1380 scroll_amount);
1381 if (!tem) stop_vpos = height;
1382 }
1383 }
1384
1385 /* In any case, do not display past bottom of window */
1386 if (stop_vpos >= height)
1387 {
1388 stop_vpos = height;
1389 scroll_amount = 0;
1390 }
1391
1392 /* Handle case where pos is before w->start --
1393 can happen if part of line had been clipped and is not clipped now */
1394 if (vpos == 0 && pos < marker_position (w->start))
1395 Fset_marker (w->start, make_number (pos), Qnil);
1396
1397 /* Redisplay the lines where the text was changed */
1398 last_text_vpos = vpos;
1399 tab_offset = pos_tab_offset (w, pos);
1400 /* If we are starting display in mid-character, correct tab_offset
1401 to account for passing the line that that character really starts in. */
1402 if (val.hpos < lmargin)
1403 tab_offset += width;
1404 while (vpos < stop_vpos)
1405 {
1406 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
1407 tab_offset += width;
1408 if (val.vpos) tab_offset = 0;
1409 if (pos != val.bufpos)
1410 last_text_vpos
1411 /* Next line, unless prev line ended in end of buffer with no cr */
1412 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
1413 pos = val.bufpos;
1414 }
1415
1416 /* There are two cases:
1417 1) we have displayed down to the bottom of the window
1418 2) we have scrolled lines below stop_vpos by scroll_amount */
1419
1420 if (vpos == height)
1421 {
1422 /* If last line is continued in middle of character,
1423 include the split character in the text considered on the frame */
1424 if (val.hpos < lmargin)
1425 val.bufpos++;
1426 XFASTINT (w->window_end_vpos) = last_text_vpos;
1427 XFASTINT (w->window_end_pos) = Z - val.bufpos;
1428 }
1429
1430 /* If scrolling made blank lines at window bottom,
1431 redisplay to fill those lines */
1432 if (scroll_amount < 0)
1433 {
1434 /* Don't consider these lines for general-purpose scrolling.
1435 That will save time in the scrolling computation. */
1436 FRAME_SCROLL_BOTTOM_VPOS (f) = xp.vpos;
1437 vpos = xp.vpos;
1438 pos = xp.bufpos;
1439 val.hpos = lmargin;
1440 if (pos == ZV)
1441 vpos = height + scroll_amount;
1442 else if (xp.contin && xp.hpos != lmargin)
1443 {
1444 val.hpos = xp.prevhpos - width + lmargin;
1445 pos--;
1446 }
1447
1448 blank_end_of_window = 1;
1449 tab_offset = pos_tab_offset (w, pos);
1450 /* If we are starting display in mid-character, correct tab_offset
1451 to account for passing the line that that character starts in. */
1452 if (val.hpos < lmargin)
1453 tab_offset += width;
1454
1455 while (vpos < height)
1456 {
1457 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
1458 tab_offset += width;
1459 if (val.vpos) tab_offset = 0;
1460 pos = val.bufpos;
1461 }
1462
1463 /* Here is a case where display_text_line sets cursor_vpos wrong.
1464 Make it be fixed up, below. */
1465 if (xp.bufpos == ZV
1466 && xp.bufpos == point)
1467 cursor_vpos = -1;
1468 }
1469
1470 /* If bottom just moved off end of frame, change mode line percentage. */
1471 if (XFASTINT (w->window_end_pos) == 0
1472 && Z != val.bufpos)
1473 w->update_mode_line = Qt;
1474
1475 /* Attempt to adjust end-of-text positions to new bottom line */
1476 if (scroll_amount)
1477 {
1478 delta = height - xp.vpos;
1479 if (delta < 0
1480 || (delta > 0 && xp.bufpos <= ZV)
1481 || (delta == 0 && xp.hpos))
1482 {
1483 val = *vmotion (Z - XFASTINT (w->window_end_pos),
1484 delta, width, hscroll, window);
1485 XFASTINT (w->window_end_pos) = Z - val.bufpos;
1486 XFASTINT (w->window_end_vpos) += val.vpos;
1487 }
1488 }
1489
1490 w->window_end_valid = Qnil;
1491
1492 /* If point was not in a line that was displayed, find it */
1493 if (cursor_vpos < 0)
1494 {
1495 val = *compute_motion (start, 0, lmargin, point, 10000, 10000,
1496 width, hscroll, pos_tab_offset (w, start));
1497 /* Admit failure if point is off frame now */
1498 if (val.vpos >= height)
1499 {
1500 for (vpos = 0; vpos < height; vpos++)
1501 cancel_line (vpos + top, f);
1502 return 0;
1503 }
1504 cursor_vpos = val.vpos + top;
1505 cursor_hpos = val.hpos + XFASTINT (w->left);
1506 }
1507
1508 FRAME_CURSOR_X (f) = max (0, cursor_hpos);
1509 FRAME_CURSOR_Y (f) = cursor_vpos;
1510
1511 if (debug_end_pos)
1512 {
1513 val = *compute_motion (start, 0, lmargin, ZV,
1514 height, - (1 << (SHORTBITS - 1)),
1515 width, hscroll, pos_tab_offset (w, start));
1516 if (val.vpos != XFASTINT (w->window_end_vpos))
1517 abort ();
1518 if (XFASTINT (w->window_end_pos)
1519 != Z - val.bufpos)
1520 abort ();
1521 }
1522
1523 return 1;
1524 }
1525 \f
1526 /* Mark a section of BUF as modified, but only for the sake of redisplay.
1527 This is useful for recording changes to overlays.
1528
1529 We increment the buffer's modification timestamp and set the
1530 redisplay caches (windows_or_buffers_changed, beg_unchanged, etc)
1531 as if the region of text between START and END had been modified;
1532 the redisplay code will check this against the windows' timestamps,
1533 and redraw the appropriate area of the buffer.
1534
1535 However, if the buffer is unmodified, we bump the last-save
1536 timestamp as well, so that incrementing the timestamp doesn't fool
1537 Emacs into thinking that the buffer's text has been modified.
1538
1539 Tweaking the timestamps shouldn't hurt the first-modification
1540 timestamps recorded in the undo records; those values aren't
1541 written until just before a real text modification is made, so they
1542 will never catch the timestamp value just before this function gets
1543 called. */
1544
1545 void
1546 redisplay_region (buf, start, end)
1547 struct buffer *buf;
1548 int start, end;
1549 {
1550 if (start == end)
1551 return;
1552
1553 if (start > end)
1554 {
1555 int temp = start;
1556 start = end; end = temp;
1557 }
1558
1559 if (buf != current_buffer)
1560 windows_or_buffers_changed = 1;
1561 else
1562 {
1563 if (unchanged_modified == MODIFF)
1564 {
1565 beg_unchanged = start - BEG;
1566 end_unchanged = Z - end;
1567 }
1568 else
1569 {
1570 if (Z - end < end_unchanged)
1571 end_unchanged = Z - end;
1572 if (start - BEG < beg_unchanged)
1573 beg_unchanged = start - BEG;
1574 }
1575 }
1576
1577 /* Increment the buffer's time stamp, but also increment the save
1578 and autosave timestamps, so as not to screw up that timekeeping. */
1579 if (BUF_MODIFF (buf) == buf->save_modified)
1580 buf->save_modified++;
1581 if (BUF_MODIFF (buf) == buf->auto_save_modified)
1582 buf->auto_save_modified++;
1583
1584 BUF_MODIFF (buf) ++;
1585 }
1586
1587 \f
1588 /* Copy glyphs from the vector FROM to the rope T.
1589 But don't actually copy the parts that would come in before S.
1590 Value is T, advanced past the copied data. */
1591
1592 GLYPH *
1593 copy_rope (t, s, from, face)
1594 register GLYPH *t; /* Copy to here. */
1595 register GLYPH *s; /* Starting point. */
1596 Lisp_Object from; /* Data to copy; known to be a vector. */
1597 int face; /* Face to apply to glyphs which don't specify one. */
1598 {
1599 register int n = XVECTOR (from)->size;
1600 register Lisp_Object *f = XVECTOR (from)->contents;
1601
1602 while (n--)
1603 {
1604 int glyph = XFASTINT (*f);
1605
1606 if (t >= s) *t = MAKE_GLYPH (GLYPH_CHAR (glyph),
1607 (GLYPH_FACE (glyph)
1608 ? GLYPH_FACE (glyph)
1609 : face));
1610 ++t;
1611 ++f;
1612 }
1613 return t;
1614 }
1615
1616 /* Copy exactly LEN glyphs from FROM into data at T.
1617 But don't alter words before S. */
1618
1619 GLYPH *
1620 copy_part_of_rope (t, s, from, len, face)
1621 register GLYPH *t; /* Copy to here. */
1622 register GLYPH *s; /* Starting point. */
1623 Lisp_Object *from; /* Data to copy. */
1624 int len;
1625 int face; /* Face to apply to glyphs which don't specify one. */
1626 {
1627 int n = len;
1628 register Lisp_Object *f = from;
1629
1630 while (n--)
1631 {
1632 int glyph = XFASTINT (*f);
1633
1634 if (t >= s) *t = MAKE_GLYPH (GLYPH_CHAR (glyph),
1635 (GLYPH_FACE (glyph)
1636 ? GLYPH_FACE (glyph)
1637 : face));
1638 ++t;
1639 ++f;
1640 }
1641 return t;
1642 }
1643 \f
1644 /* Display one line of window w, starting at position START in W's buffer.
1645 Display starting at horizontal position HPOS, which is normally zero
1646 or negative. A negative value causes output up to hpos = 0 to be discarded.
1647 This is done for negative hscroll, or when this is a continuation line
1648 and the continuation occurred in the middle of a multi-column character.
1649
1650 TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
1651
1652 Display on position VPOS on the frame. (origin 0).
1653
1654 Returns a STRUCT POSITION giving character to start next line with
1655 and where to display it, including a zero or negative hpos.
1656 The vpos field is not really a vpos; it is 1 unless the line is continued */
1657
1658 struct position val_display_text_line;
1659
1660 static struct position *
1661 display_text_line (w, start, vpos, hpos, taboffset)
1662 struct window *w;
1663 int start;
1664 int vpos;
1665 int hpos;
1666 int taboffset;
1667 {
1668 register int pos = start;
1669 register int c;
1670 register GLYPH *p1;
1671 int end;
1672 register int pause;
1673 register unsigned char *p;
1674 GLYPH *endp;
1675 register GLYPH *startp;
1676 register GLYPH *p1prev = 0;
1677 FRAME_PTR f = XFRAME (w->frame);
1678 int tab_width = XINT (current_buffer->tab_width);
1679 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
1680 int width = window_internal_width (w) - 1;
1681 struct position val;
1682 int lastpos;
1683 int invis;
1684 int hscroll = XINT (w->hscroll);
1685 int truncate = hscroll
1686 || (truncate_partial_width_windows
1687 && XFASTINT (w->width) < FRAME_WIDTH (f))
1688 || !NILP (current_buffer->truncate_lines);
1689
1690 /* 1 if we should highlight the region. */
1691 int highlight_region
1692 = !NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active);
1693 int region_beg, region_end;
1694
1695 int selective
1696 = XTYPE (current_buffer->selective_display) == Lisp_Int
1697 ? XINT (current_buffer->selective_display)
1698 : !NILP (current_buffer->selective_display) ? -1 : 0;
1699 register struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
1700 register struct Lisp_Vector *dp = window_display_table (w);
1701
1702 Lisp_Object default_invis_vector[3];
1703 /* Nonzero means display something where there are invisible lines.
1704 The precise value is the number of glyphs to display. */
1705 int selective_rlen
1706 = (selective && dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector
1707 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size
1708 : selective && !NILP (current_buffer->selective_display_ellipses)
1709 ? 3 : 0);
1710 /* This is the sequence of Lisp objects to display
1711 when there are invisible lines. */
1712 Lisp_Object *invis_vector_contents
1713 = (dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector
1714 ? XVECTOR (DISP_INVIS_VECTOR (dp))->contents
1715 : default_invis_vector);
1716
1717 GLYPH truncator = (dp == 0 || XTYPE (DISP_TRUNC_GLYPH (dp)) != Lisp_Int
1718 ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
1719 GLYPH continuer = (dp == 0 || XTYPE (DISP_CONTINUE_GLYPH (dp)) != Lisp_Int
1720 ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
1721
1722 /* The next buffer location at which the face should change, due
1723 to overlays or text property changes. */
1724 int next_face_change;
1725
1726 /* The face we're currently using. */
1727 int current_face = 0;
1728
1729 XFASTINT (default_invis_vector[2]) = '.';
1730 default_invis_vector[0] = default_invis_vector[1] = default_invis_vector[2];
1731
1732 hpos += XFASTINT (w->left);
1733 get_display_line (f, vpos, XFASTINT (w->left));
1734 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
1735
1736 /* Show where to highlight the region. */
1737 if (highlight_region && XMARKER (current_buffer->mark)->buffer != 0
1738 /* Maybe highlight only in selected window. */
1739 && (highlight_nonselected_windows
1740 || w == XWINDOW (selected_window)))
1741 {
1742 region_beg = marker_position (current_buffer->mark);
1743 if (PT < region_beg)
1744 {
1745 region_end = region_beg;
1746 region_beg = PT;
1747 }
1748 else
1749 region_end = PT;
1750 w->region_showing = Qt;
1751 }
1752 else
1753 region_beg = region_end = -1;
1754
1755 if (MINI_WINDOW_P (w) && start == 1
1756 && vpos == XFASTINT (w->top))
1757 {
1758 if (minibuf_prompt)
1759 hpos = display_string (w, vpos, minibuf_prompt, hpos,
1760 (!truncate ? continuer : truncator),
1761 -1, -1);
1762 minibuf_prompt_width = hpos;
1763 }
1764
1765 desired_glyphs->bufp[vpos] = pos;
1766 p1 = desired_glyphs->glyphs[vpos] + hpos;
1767 end = ZV;
1768 startp = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
1769 endp = startp + width;
1770
1771 /* Arrange the overlays nicely for our purposes. Usually, we call
1772 display_text_line on only one line at a time, in which case this
1773 can't really hurt too much, or we call it on lines which appear
1774 one after another in the buffer, in which case all calls to
1775 recenter_overlay_lists but the first will be pretty cheap. */
1776 recenter_overlay_lists (current_buffer, pos);
1777
1778 /* Loop generating characters.
1779 Stop at end of buffer, before newline,
1780 if reach or pass continuation column,
1781 or at face change. */
1782 pause = pos;
1783 next_face_change = pos;
1784 while (p1 < endp)
1785 {
1786 p1prev = p1;
1787 if (pos >= pause)
1788 {
1789 /* Did we hit the end of the visible region of the buffer?
1790 Stop here. */
1791 if (pos >= end)
1792 break;
1793
1794 /* Did we reach point? Record the cursor location. */
1795 if (pos == point && cursor_vpos < 0)
1796 {
1797 cursor_vpos = vpos;
1798 cursor_hpos = p1 - startp;
1799 }
1800
1801 #ifdef HAVE_X_WINDOWS
1802 /* Did we hit a face change? Figure out what face we should
1803 use now. We also hit this the first time through the
1804 loop, to see what face we should start with. */
1805 if (pos == next_face_change && FRAME_X_P (f))
1806 current_face = compute_char_face (f, w, pos,
1807 region_beg, region_end,
1808 &next_face_change);
1809 #endif
1810
1811 pause = end;
1812
1813 if (pos < next_face_change && next_face_change < pause)
1814 pause = next_face_change;
1815
1816 /* Wouldn't you hate to read the next line to someone over
1817 the phone? */
1818 if (pos < point && point < pause)
1819 pause = point;
1820 if (pos < GPT && GPT < pause)
1821 pause = GPT;
1822
1823 p = &FETCH_CHAR (pos);
1824 }
1825 c = *p++;
1826 if (c >= 040 && c < 0177
1827 && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
1828 {
1829 if (p1 >= startp)
1830 *p1 = MAKE_GLYPH (c, current_face);
1831 p1++;
1832 }
1833 else if (c == '\n')
1834 {
1835 invis = 0;
1836 while (pos < end
1837 && selective > 0
1838 && position_indentation (pos + 1) >= selective)
1839 {
1840 invis = 1;
1841 pos = find_next_newline (pos + 1, 1);
1842 if (FETCH_CHAR (pos - 1) == '\n')
1843 pos--;
1844 }
1845 if (invis && selective_rlen > 0 && p1 >= startp)
1846 {
1847 p1 += selective_rlen;
1848 if (p1 - startp > width)
1849 p1 = endp;
1850 copy_part_of_rope (p1prev, p1prev, invis_vector_contents,
1851 (p1 - p1prev), current_face);
1852 }
1853 #if 1
1854 /* Draw the face of the newline character as extending all the
1855 way to the end of the frame line. */
1856 if (current_face)
1857 while (p1 < endp)
1858 *p1++ = MAKE_GLYPH (' ', current_face);
1859 #endif
1860 break;
1861 }
1862 else if (c == '\t')
1863 {
1864 do
1865 {
1866 if (p1 >= startp && p1 < endp)
1867 *p1 = MAKE_GLYPH (' ', current_face);
1868 p1++;
1869 }
1870 while ((p1 - startp + taboffset + hscroll - (hscroll > 0))
1871 % tab_width);
1872 }
1873 else if (c == Ctl ('M') && selective == -1)
1874 {
1875 pos = find_next_newline (pos, 1);
1876 if (FETCH_CHAR (pos - 1) == '\n')
1877 pos--;
1878 if (selective_rlen > 0)
1879 {
1880 p1 += selective_rlen;
1881 if (p1 - startp > width)
1882 p1 = endp;
1883 copy_part_of_rope (p1prev, p1prev, invis_vector_contents,
1884 (p1 - p1prev), current_face);
1885 }
1886 #if 1
1887 /* Draw the face of the newline character as extending all the
1888 way to the end of the frame line. */
1889 if (current_face)
1890 while (p1 < endp)
1891 *p1++ = MAKE_GLYPH (' ', current_face);
1892 #endif
1893 break;
1894 }
1895 else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
1896 {
1897 p1 = copy_rope (p1, startp, DISP_CHAR_VECTOR (dp, c), current_face);
1898 }
1899 else if (c < 0200 && ctl_arrow)
1900 {
1901 if (p1 >= startp)
1902 *p1 = MAKE_GLYPH ((dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
1903 ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
1904 current_face);
1905 p1++;
1906 if (p1 >= startp && p1 < endp)
1907 *p1 = MAKE_GLYPH (c ^ 0100, current_face);
1908 p1++;
1909 }
1910 else
1911 {
1912 if (p1 >= startp)
1913 *p1 = MAKE_GLYPH ((dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
1914 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
1915 current_face);
1916 p1++;
1917 if (p1 >= startp && p1 < endp)
1918 *p1 = MAKE_GLYPH ((c >> 6) + '0', current_face);
1919 p1++;
1920 if (p1 >= startp && p1 < endp)
1921 *p1 = MAKE_GLYPH ((7 & (c >> 3)) + '0', current_face);
1922 p1++;
1923 if (p1 >= startp && p1 < endp)
1924 *p1 = MAKE_GLYPH ((7 & c) + '0', current_face);
1925 p1++;
1926 }
1927
1928 pos++;
1929 }
1930
1931 val.hpos = - XINT (w->hscroll);
1932 if (val.hpos)
1933 val.hpos++;
1934
1935 val.vpos = 1;
1936
1937 lastpos = pos;
1938
1939 /* Handle continuation in middle of a character */
1940 /* by backing up over it */
1941 if (p1 > endp)
1942 {
1943 /* Don't back up if we never actually displayed any text.
1944 This occurs when the minibuffer prompt takes up the whole line. */
1945 if (p1prev)
1946 {
1947 /* Start the next line with that same character */
1948 pos--;
1949 /* but at negative hpos, to skip the columns output on this line. */
1950 val.hpos += p1prev - endp;
1951 }
1952
1953 /* Keep in this line everything up to the continuation column. */
1954 p1 = endp;
1955 }
1956
1957 /* Finish deciding which character to start the next line on,
1958 and what hpos to start it at.
1959 Also set `lastpos' to the last position which counts as "on this line"
1960 for cursor-positioning. */
1961
1962 if (pos < ZV)
1963 {
1964 if (FETCH_CHAR (pos) == '\n')
1965 /* If stopped due to a newline, start next line after it */
1966 pos++;
1967 else
1968 /* Stopped due to right margin of window */
1969 {
1970 if (truncate)
1971 {
1972 *p1++ = truncator;
1973 /* Truncating => start next line after next newline,
1974 and point is on this line if it is before the newline,
1975 and skip none of first char of next line */
1976 pos = find_next_newline (pos, 1);
1977 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
1978
1979 lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
1980 }
1981 else
1982 {
1983 *p1++ = continuer;
1984 val.vpos = 0;
1985 lastpos--;
1986 }
1987 }
1988 }
1989
1990 /* If point is at eol or in invisible text at eol,
1991 record its frame location now. */
1992
1993 if (start <= point && point <= lastpos && cursor_vpos < 0)
1994 {
1995 cursor_vpos = vpos;
1996 cursor_hpos = p1 - startp;
1997 }
1998
1999 if (cursor_vpos == vpos)
2000 {
2001 if (cursor_hpos < 0) cursor_hpos = 0;
2002 if (cursor_hpos > width) cursor_hpos = width;
2003 cursor_hpos += XFASTINT (w->left);
2004 if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
2005 {
2006 FRAME_CURSOR_Y (f) = cursor_vpos;
2007 FRAME_CURSOR_X (f) = cursor_hpos;
2008
2009 if (w == XWINDOW (selected_window))
2010 {
2011 /* Line is not continued and did not start
2012 in middle of character */
2013 if ((hpos - XFASTINT (w->left)
2014 == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
2015 && val.vpos)
2016 {
2017 this_line_bufpos = start;
2018 this_line_buffer = current_buffer;
2019 this_line_vpos = cursor_vpos;
2020 this_line_start_hpos = hpos;
2021 this_line_endpos = Z - lastpos;
2022 }
2023 else
2024 this_line_bufpos = 0;
2025 }
2026 }
2027 }
2028
2029 /* If hscroll and line not empty, insert truncation-at-left marker */
2030 if (hscroll && lastpos != start)
2031 {
2032 *startp = truncator;
2033 if (p1 <= startp)
2034 p1 = startp + 1;
2035 }
2036
2037 if (XFASTINT (w->width) + XFASTINT (w->left) != FRAME_WIDTH (f))
2038 {
2039 endp++;
2040 if (p1 < startp) p1 = startp;
2041 while (p1 < endp) *p1++ = SPACEGLYPH;
2042
2043 /* Don't draw vertical bars if we're using scroll bars. They're
2044 covered up by the scroll bars, and it's distracting to see
2045 them when the scroll bar windows are flickering around to be
2046 reconfigured. */
2047 *p1++ = (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
2048 ? ' ' : '|');
2049 }
2050 desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
2051 p1 - desired_glyphs->glyphs[vpos]);
2052 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
2053
2054 /* If the start of this line is the overlay arrow-position,
2055 then put the arrow string into the display-line. */
2056
2057 if (XTYPE (Voverlay_arrow_position) == Lisp_Marker
2058 && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
2059 && start == marker_position (Voverlay_arrow_position)
2060 && XTYPE (Voverlay_arrow_string) == Lisp_String
2061 && ! overlay_arrow_seen)
2062 {
2063 unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
2064 int i;
2065 int len = XSTRING (Voverlay_arrow_string)->size;
2066 int arrow_end;
2067
2068 if (len > width)
2069 len = width;
2070 for (i = 0; i < len; i++)
2071 startp[i] = p[i];
2072
2073 /* Bug in SunOS 4.1.1 compiler requires this intermediate variable. */
2074 arrow_end = (startp - desired_glyphs->glyphs[vpos]) + len;
2075 if (desired_glyphs->used[vpos] < arrow_end)
2076 desired_glyphs->used[vpos] = arrow_end;
2077
2078 overlay_arrow_seen = 1;
2079 }
2080
2081 val.bufpos = pos;
2082 val_display_text_line = val;
2083 return &val_display_text_line;
2084 }
2085 \f
2086 /* Redisplay the menu bar in the frame for window W. */
2087
2088 static void
2089 display_menu_bar (w)
2090 struct window *w;
2091 {
2092 Lisp_Object items, tail;
2093 register int vpos = 0;
2094 register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2095 int maxendcol = FRAME_WIDTH (f);
2096 int hpos = 0;
2097
2098 if (FRAME_MENU_BAR_LINES (f) <= 0)
2099 return;
2100
2101 get_display_line (f, vpos, 0);
2102
2103 /* If the user has switched buffers or windows, we need to
2104 recompute to reflect the new bindings. But we'll
2105 recompute when update_mode_lines is set too; that means
2106 that people can use force-mode-line-update to request
2107 that the menu bar be recomputed. The adverse effect on
2108 the rest of the redisplay algorithm is about the same as
2109 windows_or_buffers_changed anyway. */
2110 if (windows_or_buffers_changed
2111 || update_mode_lines
2112 || (XFASTINT (w->last_modified) < MODIFF
2113 && (XFASTINT (w->last_modified)
2114 <= XBUFFER (w->buffer)->save_modified)))
2115 {
2116 struct buffer *prev = current_buffer;
2117 current_buffer = XBUFFER (w->buffer);
2118 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items ();
2119 current_buffer = prev;
2120 }
2121
2122 for (tail = FRAME_MENU_BAR_ITEMS (f); CONSP (tail); tail = XCONS (tail)->cdr)
2123 {
2124 Lisp_Object string;
2125
2126 string = XCONS (XCONS (XCONS (tail)->car)->cdr)->car;
2127
2128 /* Record in each item its hpos. */
2129 XFASTINT (XCONS (XCONS (XCONS (tail)->car)->cdr)->cdr) = hpos;
2130
2131 if (hpos < maxendcol)
2132 hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
2133 XSTRING (string)->data,
2134 hpos, 0, hpos, maxendcol);
2135 /* Put a gap of 3 spaces between items. */
2136 if (hpos < maxendcol)
2137 {
2138 int hpos1 = hpos + 3;
2139 hpos = display_string (w, vpos, "", hpos, 0,
2140 min (hpos1, maxendcol), maxendcol);
2141 }
2142 }
2143
2144 FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
2145 FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
2146
2147 /* Fill out the line with spaces. */
2148 if (maxendcol > hpos)
2149 hpos = display_string (w, vpos, "", hpos, 0, maxendcol, -1);
2150 }
2151 \f
2152 /* Display the mode line for window w */
2153
2154 static void
2155 display_mode_line (w)
2156 struct window *w;
2157 {
2158 register int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
2159 register int left = XFASTINT (w->left);
2160 register int right = XFASTINT (w->width) + left;
2161 register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2162
2163 line_number_displayed = 0;
2164
2165 get_display_line (f, vpos, left);
2166 display_mode_element (w, vpos, left, 0, right, right,
2167 current_buffer->mode_line_format);
2168 FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
2169
2170 /* Make the mode line inverse video if the entire line
2171 is made of mode lines.
2172 I.e. if this window is full width,
2173 or if it is the child of a full width window
2174 (which implies that that window is split side-by-side
2175 and the rest of this line is mode lines of the sibling windows). */
2176 if (XFASTINT (w->width) == FRAME_WIDTH (f)
2177 || XFASTINT (XWINDOW (w->parent)->width) == FRAME_WIDTH (f))
2178 FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
2179
2180 #ifdef HAVE_X_WINDOWS
2181 /* I'm trying this out because I saw Unimpress use it, but it's
2182 possible that this may mess adversely with some window managers. -jla
2183
2184 Wouldn't it be nice to use something like mode-line-format to
2185 describe frame titles? -JimB */
2186
2187 /* Change the title of the frame to the name of the buffer displayed
2188 in the currently selected window. Don't do this for minibuffer frames,
2189 and don't do it when there's only one non-minibuffer frame. */
2190 if (FRAME_X_P (f)
2191 && ! FRAME_MINIBUF_ONLY_P (f)
2192 && w == XWINDOW (f->selected_window))
2193 x_implicitly_set_name (f, (EQ (Fnext_frame (WINDOW_FRAME (w), Qnil),
2194 WINDOW_FRAME (w))
2195 ? Qnil
2196 : XBUFFER (w->buffer)->name),
2197 Qnil);
2198 #endif
2199 }
2200
2201 /* Contribute ELT to the mode line for window W.
2202 How it translates into text depends on its data type.
2203
2204 VPOS is the position of the mode line being displayed.
2205
2206 HPOS is the position (absolute on frame) where this element's text
2207 should start. The output is truncated automatically at the right
2208 edge of window W.
2209
2210 DEPTH is the depth in recursion. It is used to prevent
2211 infinite recursion here.
2212
2213 MINENDCOL is the hpos before which the element may not end.
2214 The element is padded at the right with spaces if nec
2215 to reach this column.
2216
2217 MAXENDCOL is the hpos past which this element may not extend.
2218 If MINENDCOL is > MAXENDCOL, MINENDCOL takes priority.
2219 (This is necessary to make nested padding and truncation work.)
2220
2221 Returns the hpos of the end of the text generated by ELT.
2222 The next element will receive that value as its HPOS arg,
2223 so as to concatenate the elements. */
2224
2225 static int
2226 display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
2227 struct window *w;
2228 register int vpos, hpos;
2229 int depth;
2230 int minendcol;
2231 register int maxendcol;
2232 register Lisp_Object elt;
2233 {
2234 tail_recurse:
2235 if (depth > 10)
2236 goto invalid;
2237
2238 depth++;
2239
2240 #ifdef SWITCH_ENUM_BUG
2241 switch ((int) XTYPE (elt))
2242 #else
2243 switch (XTYPE (elt))
2244 #endif
2245 {
2246 case Lisp_String:
2247 {
2248 /* A string: output it and check for %-constructs within it. */
2249 register unsigned char c;
2250 register unsigned char *this = XSTRING (elt)->data;
2251
2252 while (hpos < maxendcol && *this)
2253 {
2254 unsigned char *last = this;
2255 while ((c = *this++) != '\0' && c != '%')
2256 ;
2257 if (this - 1 != last)
2258 {
2259 register int lim = --this - last + hpos;
2260 hpos = display_string (w, vpos, last, hpos, 0, hpos,
2261 min (lim, maxendcol));
2262 }
2263 else /* c == '%' */
2264 {
2265 register int spec_width = 0;
2266
2267 /* We can't allow -ve args due to the "%-" construct */
2268 /* Argument specifies minwidth but not maxwidth
2269 (maxwidth can be specified by
2270 (<negative-number> . <stuff>) mode-line elements) */
2271
2272 while ((c = *this++) >= '0' && c <= '9')
2273 {
2274 spec_width = spec_width * 10 + (c - '0');
2275 }
2276
2277 spec_width += hpos;
2278 if (spec_width > maxendcol)
2279 spec_width = maxendcol;
2280
2281 if (c == 'M')
2282 hpos = display_mode_element (w, vpos, hpos, depth,
2283 spec_width, maxendcol,
2284 Vglobal_mode_string);
2285 else if (c != 0)
2286 hpos = display_string (w, vpos,
2287 decode_mode_spec (w, c,
2288 maxendcol - hpos),
2289 hpos, 0, spec_width, maxendcol);
2290 }
2291 }
2292 }
2293 break;
2294
2295 case Lisp_Symbol:
2296 /* A symbol: process the value of the symbol recursively
2297 as if it appeared here directly. Avoid error if symbol void.
2298 Special case: if value of symbol is a string, output the string
2299 literally. */
2300 {
2301 register Lisp_Object tem;
2302 tem = Fboundp (elt);
2303 if (!NILP (tem))
2304 {
2305 tem = Fsymbol_value (elt);
2306 /* If value is a string, output that string literally:
2307 don't check for % within it. */
2308 if (XTYPE (tem) == Lisp_String)
2309 hpos = display_string (w, vpos, XSTRING (tem)->data,
2310 hpos, 0, minendcol, maxendcol);
2311 /* Give up right away for nil or t. */
2312 else if (!EQ (tem, elt))
2313 { elt = tem; goto tail_recurse; }
2314 }
2315 }
2316 break;
2317
2318 case Lisp_Cons:
2319 {
2320 register Lisp_Object car, tem;
2321
2322 /* A cons cell: three distinct cases.
2323 If first element is a string or a cons, process all the elements
2324 and effectively concatenate them.
2325 If first element is a negative number, truncate displaying cdr to
2326 at most that many characters. If positive, pad (with spaces)
2327 to at least that many characters.
2328 If first element is a symbol, process the cadr or caddr recursively
2329 according to whether the symbol's value is non-nil or nil. */
2330 car = XCONS (elt)->car;
2331 if (XTYPE (car) == Lisp_Symbol)
2332 {
2333 tem = Fboundp (car);
2334 elt = XCONS (elt)->cdr;
2335 if (XTYPE (elt) != Lisp_Cons)
2336 goto invalid;
2337 /* elt is now the cdr, and we know it is a cons cell.
2338 Use its car if CAR has a non-nil value. */
2339 if (!NILP (tem))
2340 {
2341 tem = Fsymbol_value (car);
2342 if (!NILP (tem))
2343 { elt = XCONS (elt)->car; goto tail_recurse; }
2344 }
2345 /* Symbol's value is nil (or symbol is unbound)
2346 Get the cddr of the original list
2347 and if possible find the caddr and use that. */
2348 elt = XCONS (elt)->cdr;
2349 if (NILP (elt))
2350 break;
2351 else if (XTYPE (elt) != Lisp_Cons)
2352 goto invalid;
2353 elt = XCONS (elt)->car;
2354 goto tail_recurse;
2355 }
2356 else if (XTYPE (car) == Lisp_Int)
2357 {
2358 register int lim = XINT (car);
2359 elt = XCONS (elt)->cdr;
2360 if (lim < 0)
2361 /* Negative int means reduce maximum width.
2362 DO NOT change MINENDCOL here!
2363 (20 -10 . foo) should truncate foo to 10 col
2364 and then pad to 20. */
2365 maxendcol = min (maxendcol, hpos - lim);
2366 else if (lim > 0)
2367 {
2368 /* Padding specified. Don't let it be more than
2369 current maximum. */
2370 lim += hpos;
2371 if (lim > maxendcol)
2372 lim = maxendcol;
2373 /* If that's more padding than already wanted, queue it.
2374 But don't reduce padding already specified even if
2375 that is beyond the current truncation point. */
2376 if (lim > minendcol)
2377 minendcol = lim;
2378 }
2379 goto tail_recurse;
2380 }
2381 else if (XTYPE (car) == Lisp_String || XTYPE (car) == Lisp_Cons)
2382 {
2383 register int limit = 50;
2384 /* LIMIT is to protect against circular lists. */
2385 while (XTYPE (elt) == Lisp_Cons && --limit > 0
2386 && hpos < maxendcol)
2387 {
2388 hpos = display_mode_element (w, vpos, hpos, depth,
2389 hpos, maxendcol,
2390 XCONS (elt)->car);
2391 elt = XCONS (elt)->cdr;
2392 }
2393 }
2394 }
2395 break;
2396
2397 default:
2398 invalid:
2399 return (display_string (w, vpos, "*invalid*", hpos, 0,
2400 minendcol, maxendcol));
2401 }
2402
2403 end:
2404 if (minendcol > hpos)
2405 hpos = display_string (w, vpos, "", hpos, 0, minendcol, -1);
2406 return hpos;
2407 }
2408 \f
2409 /* Return a string for the output of a mode line %-spec for window W,
2410 generated by character C and width MAXWIDTH. */
2411
2412 static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
2413
2414 static char *
2415 decode_mode_spec (w, c, maxwidth)
2416 struct window *w;
2417 register char c;
2418 register int maxwidth;
2419 {
2420 Lisp_Object obj = Qnil;
2421 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2422 char *decode_mode_spec_buf = (char *) FRAME_TEMP_GLYPHS (f)->total_contents;
2423
2424 if (maxwidth > FRAME_WIDTH (f))
2425 maxwidth = FRAME_WIDTH (f);
2426
2427 switch (c)
2428 {
2429 case 'b':
2430 obj = current_buffer->name;
2431 #if 0
2432 if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
2433 {
2434 bcopy (XSTRING (obj)->data, decode_mode_spec_buf, maxwidth - 1);
2435 decode_mode_spec_buf[maxwidth - 1] = '\\';
2436 decode_mode_spec_buf[maxwidth] = '\0';
2437 return decode_mode_spec_buf;
2438 }
2439 #endif
2440 break;
2441
2442 case 'f':
2443 obj = current_buffer->filename;
2444 #if 0
2445 if (NILP (obj))
2446 return "[none]";
2447 else if (XTYPE (obj) == Lisp_String && XSTRING (obj)->size > maxwidth)
2448 {
2449 bcopy ("...", decode_mode_spec_buf, 3);
2450 bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
2451 decode_mode_spec_buf + 3, maxwidth - 3);
2452 return decode_mode_spec_buf;
2453 }
2454 #endif
2455 break;
2456
2457 case 'l':
2458 {
2459 int startpos = marker_position (w->start);
2460 int line, linepos, topline;
2461 int nlines, junk;
2462 Lisp_Object tem;
2463 int height = XFASTINT (w->height);
2464
2465 /* If we decided that this buffer isn't suitable for line numbers,
2466 don't forget that too fast. */
2467 if (EQ (w->base_line_pos, w->buffer))
2468 return "??";
2469
2470 /* If the buffer is very big, don't waste time. */
2471 if (ZV - BEGV > line_number_display_limit)
2472 {
2473 w->base_line_pos = Qnil;
2474 w->base_line_number = Qnil;
2475 return "??";
2476 }
2477
2478 if (!NILP (w->base_line_number)
2479 && !NILP (w->base_line_pos)
2480 && XFASTINT (w->base_line_pos) <= marker_position (w->start))
2481 {
2482 line = XFASTINT (w->base_line_number);
2483 linepos = XFASTINT (w->base_line_pos);
2484 }
2485 else
2486 {
2487 line = 1;
2488 linepos = BEGV;
2489 }
2490
2491 /* Count lines from base line to window start position. */
2492 nlines = display_count_lines (linepos, startpos, startpos, &junk);
2493
2494 topline = nlines + line;
2495
2496 /* Determine a new base line, if the old one is too close
2497 or too far away, or if we did not have one.
2498 "Too close" means it's plausible a scroll-down would
2499 go back past it. */
2500 if (startpos == BEGV)
2501 {
2502 XFASTINT (w->base_line_number) = topline;
2503 XFASTINT (w->base_line_pos) = BEGV;
2504 }
2505 else if (nlines < height + 25 || nlines > height * 3 + 50
2506 || linepos == BEGV)
2507 {
2508 int limit = BEGV;
2509 int position;
2510 int distance = (height * 2 + 30) * 200;
2511
2512 if (startpos - distance > limit)
2513 limit = startpos - distance;
2514
2515 nlines = display_count_lines (startpos, limit,
2516 -(height * 2 + 30),
2517 &position);
2518 /* If we couldn't find the lines we wanted within
2519 200 chars per line,
2520 give up on line numbers for this window. */
2521 if (position == startpos - distance)
2522 {
2523 w->base_line_pos = w->buffer;
2524 w->base_line_number = Qnil;
2525 return "??";
2526 }
2527
2528 XFASTINT (w->base_line_number) = topline - nlines;
2529 XFASTINT (w->base_line_pos) = position;
2530 }
2531
2532 /* Now count lines from the start pos to point. */
2533 nlines = display_count_lines (startpos, PT, PT, &junk);
2534
2535 /* Record that we did display the line number. */
2536 line_number_displayed = 1;
2537
2538 /* Make the string to show. */
2539 sprintf (decode_mode_spec_buf, "%d", topline + nlines);
2540 return decode_mode_spec_buf;
2541 }
2542 break;
2543
2544 case 'm':
2545 obj = current_buffer->mode_name;
2546 break;
2547
2548 case 'n':
2549 if (BEGV > BEG || ZV < Z)
2550 return " Narrow";
2551 break;
2552
2553 case '*':
2554 if (!NILP (current_buffer->read_only))
2555 return "%";
2556 if (MODIFF > current_buffer->save_modified)
2557 return "*";
2558 return "-";
2559
2560 case 's':
2561 /* status of process */
2562 obj = Fget_buffer_process (Fcurrent_buffer ());
2563 if (NILP (obj))
2564 return "no process";
2565 obj = Fsymbol_name (Fprocess_status (obj));
2566 break;
2567
2568 case 'p':
2569 {
2570 int pos = marker_position (w->start);
2571 int total = ZV - BEGV;
2572
2573 if (XFASTINT (w->window_end_pos) <= Z - ZV)
2574 {
2575 if (pos <= BEGV)
2576 return "All";
2577 else
2578 return "Bottom";
2579 }
2580 else if (pos <= BEGV)
2581 return "Top";
2582 else
2583 {
2584 total = ((pos - BEGV) * 100 + total - 1) / total;
2585 /* We can't normally display a 3-digit number,
2586 so get us a 2-digit number that is close. */
2587 if (total == 100)
2588 total = 99;
2589 sprintf (decode_mode_spec_buf, "%2d%%", total);
2590 return decode_mode_spec_buf;
2591 }
2592 }
2593
2594 case '%':
2595 return "%";
2596
2597 case '[':
2598 {
2599 int i;
2600 char *p;
2601
2602 if (command_loop_level > 5)
2603 return "[[[... ";
2604 p = decode_mode_spec_buf;
2605 for (i = 0; i < command_loop_level; i++)
2606 *p++ = '[';
2607 *p = 0;
2608 return decode_mode_spec_buf;
2609 }
2610
2611 case ']':
2612 {
2613 int i;
2614 char *p;
2615
2616 if (command_loop_level > 5)
2617 return " ...]]]";
2618 p = decode_mode_spec_buf;
2619 for (i = 0; i < command_loop_level; i++)
2620 *p++ = ']';
2621 *p = 0;
2622 return decode_mode_spec_buf;
2623 }
2624
2625 case '-':
2626 {
2627 register char *p;
2628 register int i;
2629
2630 if (maxwidth < sizeof (lots_of_dashes))
2631 return lots_of_dashes;
2632 else
2633 {
2634 for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
2635 *p++ = '-';
2636 *p = '\0';
2637 }
2638 return decode_mode_spec_buf;
2639 }
2640 }
2641
2642 if (XTYPE (obj) == Lisp_String)
2643 return (char *) XSTRING (obj)->data;
2644 else
2645 return "";
2646 }
2647
2648 /* Count up to N lines starting from FROM.
2649 But don't go beyond LIMIT.
2650 Return the number of lines thus found (always positive).
2651 Store the position after what was found into *POS_PTR. */
2652
2653 static int
2654 display_count_lines (from, limit, n, pos_ptr)
2655 int from, limit, n;
2656 int *pos_ptr;
2657 {
2658 int oldbegv = BEGV;
2659 int oldzv = ZV;
2660 int shortage = 0;
2661
2662 if (limit < from)
2663 BEGV = limit;
2664 else
2665 ZV = limit;
2666
2667 *pos_ptr = scan_buffer ('\n', from, n, &shortage);
2668
2669 ZV = oldzv;
2670 BEGV = oldbegv;
2671
2672 if (n < 0)
2673 /* When scanning backwards, scan_buffer stops *after* the last newline
2674 it finds, but does count it. Compensate for that. */
2675 return - n - shortage - (*pos_ptr != limit);
2676 return n - shortage;
2677 }
2678 \f
2679 /* Display STRING on one line of window W, starting at HPOS.
2680 Display at position VPOS. Caller should have done get_display_line.
2681 If VPOS == -1, display it as the current frame's title.
2682
2683 TRUNCATE is GLYPH to display at end if truncated. Zero for none.
2684
2685 MINCOL is the first column ok to end at. (Pad with spaces to this col.)
2686 MAXCOL is the last column ok to end at. Truncate here.
2687 -1 for MINCOL or MAXCOL means no explicit minimum or maximum.
2688 Both count from the left edge of the frame, as does HPOS.
2689 The right edge of W is an implicit maximum.
2690 If TRUNCATE is nonzero, the implicit maximum is one column before the edge.
2691
2692 Returns ending hpos */
2693
2694 static int
2695 display_string (w, vpos, string, hpos, truncate, mincol, maxcol)
2696 struct window *w;
2697 unsigned char *string;
2698 int vpos, hpos;
2699 GLYPH truncate;
2700 int mincol, maxcol;
2701 {
2702 register int c;
2703 register GLYPH *p1;
2704 int hscroll = XINT (w->hscroll);
2705 int tab_width = XINT (XBUFFER (w->buffer)->tab_width);
2706 register GLYPH *start;
2707 register GLYPH *end;
2708 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2709 struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
2710 GLYPH *p1start = desired_glyphs->glyphs[vpos] + hpos;
2711 int window_width = XFASTINT (w->width);
2712
2713 /* Use the standard display table, not the window's display table.
2714 We don't want the mode line in rot13. */
2715 register struct Lisp_Vector *dp = 0;
2716
2717 if (XTYPE (Vstandard_display_table) == Lisp_Vector
2718 && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
2719 dp = XVECTOR (Vstandard_display_table);
2720
2721 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
2722
2723 p1 = p1start;
2724 start = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
2725 end = start + window_width - (truncate != 0);
2726
2727 if ((window_width + XFASTINT (w->left)) != FRAME_WIDTH (f))
2728 {
2729 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2730 {
2731 int i;
2732
2733 for (i = 0; i < VERTICAL_SCROLL_BAR_WIDTH; i++)
2734 *end-- = ' ';
2735 }
2736 else
2737 *end-- = '|';
2738 }
2739
2740 if (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol)
2741 end = desired_glyphs->glyphs[vpos] + maxcol;
2742 if (maxcol >= 0 && mincol > maxcol)
2743 mincol = maxcol;
2744
2745 while (p1 < end)
2746 {
2747 c = *string++;
2748 if (!c) break;
2749 if (c >= 040 && c < 0177
2750 && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
2751 {
2752 if (p1 >= start)
2753 *p1 = c;
2754 p1++;
2755 }
2756 else if (c == '\t')
2757 {
2758 do
2759 {
2760 if (p1 >= start && p1 < end)
2761 *p1 = SPACEGLYPH;
2762 p1++;
2763 }
2764 while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
2765 }
2766 else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
2767 p1 = copy_rope (p1, start, DISP_CHAR_VECTOR (dp, c), 0);
2768 else if (c < 0200 && ! NILP (buffer_defaults.ctl_arrow))
2769 {
2770 if (p1 >= start)
2771 *p1 = (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
2772 ? XINT (DISP_CTRL_GLYPH (dp)) : '^');
2773 p1++;
2774 if (p1 >= start && p1 < end)
2775 *p1 = c ^ 0100;
2776 p1++;
2777 }
2778 else
2779 {
2780 if (p1 >= start)
2781 *p1 = (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
2782 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\');
2783 p1++;
2784 if (p1 >= start && p1 < end)
2785 *p1 = (c >> 6) + '0';
2786 p1++;
2787 if (p1 >= start && p1 < end)
2788 *p1 = (7 & (c >> 3)) + '0';
2789 p1++;
2790 if (p1 >= start && p1 < end)
2791 *p1 = (7 & c) + '0';
2792 p1++;
2793 }
2794 }
2795
2796 if (c)
2797 {
2798 p1 = end;
2799 if (truncate) *p1++ = truncate;
2800 }
2801 else if (mincol >= 0)
2802 {
2803 end = desired_glyphs->glyphs[vpos] + mincol;
2804 while (p1 < end)
2805 *p1++ = SPACEGLYPH;
2806 }
2807
2808 {
2809 register int len = p1 - desired_glyphs->glyphs[vpos];
2810
2811 if (len > desired_glyphs->used[vpos])
2812 desired_glyphs->used[vpos] = len;
2813 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
2814
2815 return len;
2816 }
2817 }
2818 \f
2819 void
2820 syms_of_xdisp ()
2821 {
2822 staticpro (&last_arrow_position);
2823 staticpro (&last_arrow_string);
2824 last_arrow_position = Qnil;
2825 last_arrow_string = Qnil;
2826
2827 DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
2828 "String (or mode line construct) included (normally) in `mode-line-format'.");
2829 Vglobal_mode_string = Qnil;
2830
2831 DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
2832 "Marker for where to display an arrow on top of the buffer text.\n\
2833 This must be the beginning of a line in order to work.\n\
2834 See also `overlay-arrow-string'.");
2835 Voverlay_arrow_position = Qnil;
2836
2837 DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
2838 "String to display as an arrow. See also `overlay-arrow-position'.");
2839 Voverlay_arrow_string = Qnil;
2840
2841 DEFVAR_INT ("scroll-step", &scroll_step,
2842 "*The number of lines to try scrolling a window by when point moves out.\n\
2843 If that fails to bring point back on frame, point is centered instead.\n\
2844 If this is zero, point is always centered after it moves off frame.");
2845
2846 DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
2847
2848 DEFVAR_BOOL ("truncate-partial-width-windows",
2849 &truncate_partial_width_windows,
2850 "*Non-nil means truncate lines in all windows less than full frame wide.");
2851 truncate_partial_width_windows = 1;
2852
2853 DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
2854 "*Non-nil means use inverse video for the mode line.");
2855 mode_line_inverse_video = 1;
2856
2857 DEFVAR_INT ("line-number-display-limit", &line_number_display_limit,
2858 "*Maximum buffer size for which line number should be displayed.");
2859 line_number_display_limit = 1000000;
2860
2861 DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
2862 "*Non-nil means highlight region even in nonselected windows.");
2863 highlight_nonselected_windows = 1;
2864 }
2865
2866 /* initialize the window system */
2867 init_xdisp ()
2868 {
2869 Lisp_Object root_window;
2870 #ifndef COMPILER_REGISTER_BUG
2871 register
2872 #endif /* COMPILER_REGISTER_BUG */
2873 struct window *mini_w;
2874
2875 this_line_bufpos = 0;
2876
2877 mini_w = XWINDOW (minibuf_window);
2878 root_window = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (mini_w)));
2879
2880 echo_area_glyphs = 0;
2881 previous_echo_glyphs = 0;
2882
2883 if (!noninteractive)
2884 {
2885 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (root_window)));
2886 XFASTINT (XWINDOW (root_window)->top) = 0;
2887 set_window_height (root_window, FRAME_HEIGHT (f) - 1, 0);
2888 XFASTINT (mini_w->top) = FRAME_HEIGHT (f) - 1;
2889 set_window_height (minibuf_window, 1, 0);
2890
2891 XFASTINT (XWINDOW (root_window)->width) = FRAME_WIDTH (f);
2892 XFASTINT (mini_w->width) = FRAME_WIDTH (f);
2893 }
2894 }