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