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