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