*** empty log message ***
[bpt/emacs.git] / src / xdisp.c
CommitLineData
a2889657 1/* Display generation from window structure and buffer text.
de3e8b15 2 Copyright (C) 1985, 1986, 1987, 1988, 1992 Free Software Foundation, Inc.
a2889657
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21#include "config.h"
22#include <stdio.h>
23/*#include <ctype.h>*/
24#undef NULL
25#include "lisp.h"
26#include "screen.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
36extern int interrupt_input;
37extern int command_loop_level;
38
39/* Nonzero means print newline before next minibuffer message. */
40
41int noninteractive_need_newline;
42
43#define min(a, b) ((a) < (b) ? (a) : (b))
44#define max(a, b) ((a) > (b) ? (a) : (b))
45
46/* The buffer position of the first character appearing
47 entirely or partially on the current screen line.
48 Or zero, which disables the optimization for the current screen line. */
49static int this_line_bufpos;
50
51/* Number of characters past the end of this line,
52 including the terminating newline */
53static int this_line_endpos;
54
55/* The vertical position of this screen line. */
56static int this_line_vpos;
57
58/* Hpos value for start of display on this screen line.
59 Usually zero, but negative if first character really began
60 on previous line */
61static int this_line_start_hpos;
62
63/* Buffer that this_line variables are describing. */
64static struct buffer *this_line_buffer;
65
66/* Set by try_window_id to the vpos of first of any lines
67 scrolled on to the bottom of the screen. These lines should
68 not be included in any general scroll computation. */
69static int scroll_bottom_vpos;
70
71/* Value of echo_area_glyphs when it was last acted on.
72 If this is nonzero, there is a message on the screen
73 in the minibuffer and it should be erased as soon
74 as it is no longer requested to appear. */
75char *previous_echo_glyphs;
76
77/* Nonzero means truncate lines in all windows less wide than the screen */
78int truncate_partial_width_windows;
79
80Lisp_Object Vglobal_mode_string;
81
82/* Marker for where to display an arrow on top of the buffer text. */
83Lisp_Object Voverlay_arrow_position;
84
85/* String to display for the arrow. */
86Lisp_Object Voverlay_arrow_string;
87
88/* Values of those variables at last redisplay. */
89Lisp_Object last_arrow_position, last_arrow_string;
90
91/* Nonzero if overlay arrow has been displayed once in this window. */
92static int overlay_arrow_seen;
93
94/* If cursor motion alone moves point off screen,
95 Try scrolling this many lines up or down if that will bring it back. */
96int scroll_step;
97
98/* Nonzero if try_window_id has made blank lines at window bottom
99 since the last redisplay that paused */
100static int blank_end_of_window;
101
102/* Number of windows showing the buffer of the selected window.
103 keyboard.c refers to this. */
104int buffer_shared;
105
106/* display_text_line sets these to the screen position (origin 0) of point,
107 whether the window is selected or not.
108 Set one to -1 first to determine whether point was found afterwards. */
109
110static int cursor_vpos;
111static int cursor_hpos;
112
113int debug_end_pos;
114
115/* Nonzero means display mode line highlighted */
116int mode_line_inverse_video;
117
118static void echo_area_display ();
119void mark_window_display_accurate ();
120static void redisplay_windows ();
121static void redisplay_window ();
122static void try_window ();
123static int try_window_id ();
124static struct position *display_text_line ();
125static void display_mode_line ();
126static int display_mode_element ();
127static char *fmodetrunc ();
128static char *decode_mode_spec ();
129static int display_string ();
130
131/* Prompt to display in front of the minibuffer contents */
132char *minibuf_prompt;
133
134/* Width in columns of current minibuffer prompt. */
135int minibuf_prompt_width;
136
137/* Message to display instead of minibuffer contents
138 This is what the functions error and message make,
139 and command echoing uses it as well.
140 It overrides the minibuf_prompt as well as the buffer. */
141char *echo_area_glyphs;
142
143/* true iff we should redraw the mode lines on the next redisplay */
144int update_mode_lines;
145
146/* Smallest number of characters before the gap
147 at any time since last redisplay that finished.
148 Valid for current buffer when try_window_id can be called. */
149int beg_unchanged;
150
151/* Smallest number of characters after the gap
152 at any time since last redisplay that finished.
153 Valid for current buffer when try_window_id can be called. */
154int end_unchanged;
155
156/* MODIFF as of last redisplay that finished;
157 if it matches MODIFF, beg_unchanged and end_unchanged
158 contain no useful information */
159int unchanged_modified;
160
161/* Nonzero if head_clip or tail_clip of current buffer has changed
162 since last redisplay that finished */
163int clip_changed;
164
165/* Nonzero if window sizes or contents have changed
166 since last redisplay that finished */
167int windows_or_buffers_changed;
168
169\f
e5d77022 170/* Nonzero if SCREEN_MESSAGE_BUF (selected_screen) is being used by print;
9c74a0dd
JB
171 zero if being used by message. */
172int message_buf_print;
173
a2889657
JB
174/* dump an informative message to the minibuf */
175/* VARARGS 1 */
176
177void
178message (m, a1, a2, a3)
179 char *m;
180{
181 if (noninteractive)
182 {
183 if (noninteractive_need_newline)
184 putc ('\n', stderr);
185 noninteractive_need_newline = 0;
186 fprintf (stderr, m, a1, a2, a3);
187 fprintf (stderr, "\n");
188 fflush (stderr);
189 }
6e8290aa 190 /* A null message buffer means that the screen hasn't really been
8de2d90b
JB
191 initialized yet. Error messages get reported properly by
192 cmd_error, so this must be just an informative message; toss it. */
6e8290aa 193 else if (INTERACTIVE && SCREEN_MESSAGE_BUF (selected_screen))
a2889657 194 {
8de2d90b
JB
195#ifdef MULTI_SCREEN
196 choose_minibuf_screen ();
197 Fmake_screen_visible (WINDOW_SCREEN (XWINDOW (minibuf_window)));
198#endif
199
265a9e55 200 {
a2889657 201#ifdef NO_ARG_ARRAY
265a9e55
JB
202 int a[3];
203 a[0] = a1;
204 a[1] = a2;
205 a[2] = a3;
a2889657 206
265a9e55
JB
207 doprnt (SCREEN_MESSAGE_BUF (selected_screen),
208 SCREEN_WIDTH (selected_screen), m, 0, 3, a);
a2889657 209#else
265a9e55
JB
210 doprnt (SCREEN_MESSAGE_BUF (selected_screen),
211 SCREEN_WIDTH (selected_screen), m, 0, 3, &a1);
6e8290aa 212#endif /* NO_ARG_ARRAY */
265a9e55 213 }
a2889657
JB
214
215 echo_area_glyphs = SCREEN_MESSAGE_BUF (selected_screen);
9c74a0dd
JB
216
217 /* Print should start at the beginning of the message
218 buffer next time. */
219 message_buf_print = 0;
220
a2889657
JB
221 do_pending_window_change ();
222 echo_area_display ();
223 update_screen (XSCREEN (XWINDOW (minibuf_window)->screen), 1, 1);
224 do_pending_window_change ();
225 }
226}
227
228/* Specify m, a string, as a message in the minibuf. */
229void
230message1 (m)
231 char *m;
232{
a2889657
JB
233 if (noninteractive)
234 {
235 if (noninteractive_need_newline)
236 putc ('\n', stderr);
237 noninteractive_need_newline = 0;
238 fprintf (stderr, "%s\n", m);
239 fflush (stderr);
240 }
6e8290aa 241 /* A null message buffer means that the screen hasn't really been
8de2d90b
JB
242 initialized yet. Error messages get reported properly by
243 cmd_error, so this must be just an informative message; toss it. */
6e8290aa 244 else if (INTERACTIVE && SCREEN_MESSAGE_BUF (selected_screen))
a2889657 245 {
8de2d90b
JB
246#ifdef MULTI_SCREEN
247 choose_minibuf_screen ();
248 Fmake_screen_visible (WINDOW_SCREEN (XWINDOW (minibuf_window)));
249#endif
250
a2889657
JB
251 echo_area_glyphs = m;
252 do_pending_window_change ();
253 echo_area_display ();
254 update_screen (XSCREEN (XWINDOW (minibuf_window)->screen), 1, 1);
255 do_pending_window_change ();
256 }
257}
258
259static void
260echo_area_display ()
261{
262 register int vpos;
263 SCREEN_PTR s;
264
265#ifdef MULTI_SCREEN
266 choose_minibuf_screen ();
8de2d90b 267 s = XSCREEN (WINDOW_SCREEN (XWINDOW (minibuf_window)));
a2889657 268
8de2d90b 269 if (! SCREEN_VISIBLE_P (s))
a2889657
JB
270 return;
271#endif
272
273 if (screen_garbaged)
274 {
275 Fredraw_display ();
276 screen_garbaged = 0;
277 }
278
279 if (echo_area_glyphs || minibuf_level == 0)
280 {
281 vpos = XFASTINT (XWINDOW (minibuf_window)->top);
282 get_display_line (s, vpos, 0);
283 display_string (XWINDOW (minibuf_window), vpos,
284 echo_area_glyphs ? echo_area_glyphs : "",
285 0, 0, 0, SCREEN_WIDTH (s));
286
287 /* If desired cursor location is on this line, put it at end of text */
288 if (SCREEN_CURSOR_Y (s) == vpos)
e5d77022 289 SCREEN_CURSOR_X (s) = SCREEN_DESIRED_GLYPHS (s)->used[vpos];
daa37602
JB
290
291 /* Fill the rest of the minibuffer window with blank lines. */
292 {
293 int i;
294
295 for (i = vpos + 1; i < vpos + XWINDOW (minibuf_window)->height; i++)
296 {
297 get_display_line (s, i, 0);
298 display_string (XWINDOW (minibuf_window), vpos,
299 "", 0, 0, 0, SCREEN_WIDTH (s));
300 }
301 }
a2889657
JB
302 }
303 else if (!EQ (minibuf_window, selected_window))
304 windows_or_buffers_changed++;
305
306 if (EQ (minibuf_window, selected_window))
307 this_line_bufpos = 0;
308
309 previous_echo_glyphs = echo_area_glyphs;
310}
311\f
312/* Do a screen update, taking possible shortcuts into account.
313 This is the main external entry point for redisplay.
314
315 If the last redisplay displayed an echo area message and that
316 message is no longer requested, we clear the echo area
317 or bring back the minibuffer if that is in use.
318
319 Everyone would like to have a hook here to call eval,
320 but that cannot be done safely without a lot of changes elsewhere.
321 This can be called from signal handlers; with alarms set up;
322 or with synchronous processes running.
323 See the function `echo' in keyboard.c.
324 See Fcall_process; if you called it from here, it could be
325 entered recursively. */
326
327void
328redisplay ()
329{
330 register struct window *w = XWINDOW (selected_window);
331 register int pause;
332 int must_finish = 0;
333 int all_windows;
334 register int tlbufpos, tlendpos;
335 struct position pos;
336 extern int input_pending;
337
338 if (noninteractive)
339 return;
340
341 /* Notice any pending interrupt request to change screen size. */
342 do_pending_window_change ();
343
344 if (screen_garbaged)
345 {
346 Fredraw_display ();
347 screen_garbaged = 0;
348 }
349
6e8290aa
JB
350 /* Normally the message* functions will have already displayed and
351 updated the echo area, but the screen may have been trashed, or
352 the update may have been preempted, so display the echo area
353 again here. */
a2889657
JB
354 if (echo_area_glyphs || previous_echo_glyphs)
355 {
356 echo_area_display ();
357 must_finish = 1;
358 }
359
360 if (clip_changed || windows_or_buffers_changed)
361 update_mode_lines++;
362
363 /* Detect case that we need to write a star in the mode line. */
364 if (XFASTINT (w->last_modified) < MODIFF
365 && XFASTINT (w->last_modified) <= current_buffer->save_modified)
366 {
367 w->update_mode_line = Qt;
368 if (buffer_shared > 1)
369 update_mode_lines++;
370 }
371
372 SCREEN_SCROLL_BOTTOM_VPOS (XSCREEN (w->screen)) = -1;
373
374 all_windows = update_mode_lines || buffer_shared > 1;
a2889657
JB
375
376 /* If specs for an arrow have changed, do thorough redisplay
377 to ensure we remove any arrow that should no longer exist. */
378 if (Voverlay_arrow_position != last_arrow_position
379 || Voverlay_arrow_string != last_arrow_string)
380 all_windows = 1, clip_changed = 1;
381
382 tlbufpos = this_line_bufpos;
383 tlendpos = this_line_endpos;
265a9e55 384 if (!all_windows && tlbufpos > 0 && NILP (w->update_mode_line)
a2889657
JB
385 && SCREEN_VISIBLE_P (XSCREEN (w->screen))
386 /* Make sure recorded data applies to current buffer, etc */
387 && this_line_buffer == current_buffer
388 && current_buffer == XBUFFER (w->buffer)
265a9e55 389 && NILP (w->force_start)
a2889657
JB
390 /* Point must be on the line that we have info recorded about */
391 && point >= tlbufpos
392 && point <= Z - tlendpos
393 /* All text outside that line, including its final newline,
394 must be unchanged */
395 && (XFASTINT (w->last_modified) >= MODIFF
396 || (beg_unchanged >= tlbufpos - 1
397 && GPT >= tlbufpos
05ba02eb
JB
398 /* If selective display, can't optimize
399 if the changes start at the beginning of the line. */
400 && ((XTYPE (current_buffer->selective_display) == Lisp_Int
401 && XINT (current_buffer->selective_display) > 0
402 ? (beg_unchanged >= tlbufpos
403 && GPT > tlbufpos)
404 : 1))
a2889657
JB
405 && end_unchanged >= tlendpos
406 && Z - GPT >= tlendpos)))
407 {
408 if (tlbufpos > BEGV && FETCH_CHAR (tlbufpos - 1) != '\n'
409 && (tlbufpos == ZV
410 || FETCH_CHAR (tlbufpos) == '\n'))
411 /* Former continuation line has disappeared by becoming empty */
412 goto cancel;
413 else if (XFASTINT (w->last_modified) < MODIFF
414 || MINI_WINDOW_P (w))
415 {
416 cursor_vpos = -1;
417 overlay_arrow_seen = 0;
418 display_text_line (w, tlbufpos, this_line_vpos, this_line_start_hpos,
419 pos_tab_offset (w, tlbufpos));
420 /* If line contains point, is not continued,
421 and ends at same distance from eob as before, we win */
422 if (cursor_vpos >= 0 && this_line_bufpos
423 && this_line_endpos == tlendpos)
424 {
425 if (XFASTINT (w->width) != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w))))
426 preserve_other_columns (w);
427 goto update;
428 }
429 else
430 goto cancel;
431 }
432 else if (point == XFASTINT (w->last_point))
433 {
434 if (!must_finish)
435 {
436 do_pending_window_change ();
437 return;
438 }
439 goto update;
440 }
441 else
442 {
443 pos = *compute_motion (tlbufpos, 0,
444 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
445 point, 2, - (1 << (SHORTBITS - 1)),
446 XFASTINT (w->width) - 1
447 - (XFASTINT (w->width) + XFASTINT (w->left)
448 != SCREEN_WIDTH (selected_screen)),
de3e8b15
JB
449 XINT (w->hscroll),
450 pos_tab_offset (w, tlbufpos));
a2889657
JB
451 if (pos.vpos < 1)
452 {
453 SCREEN_CURSOR_X (selected_screen)
454 = XFASTINT (w->left) + max (pos.hpos, 0);
455 SCREEN_CURSOR_Y (selected_screen) = this_line_vpos;
456 goto update;
457 }
458 else
459 goto cancel;
460 }
461 cancel:
462 /* Text changed drastically or point moved off of line */
463 cancel_line (this_line_vpos, selected_screen);
464 }
465
466 this_line_bufpos = 0;
467 all_windows |= buffer_shared > 1;
468
469 if (all_windows)
470 {
471#ifdef MULTI_SCREEN
472 Lisp_Object tail;
473
474 /* Recompute # windows showing selected buffer.
8de2d90b 475 This will be incremented each time such a window is displayed. */
a2889657
JB
476 buffer_shared = 0;
477
478 for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr)
479 {
480 SCREEN_PTR s;
481
482 if (XTYPE (XCONS (tail)->car) != Lisp_Screen)
483 continue;
484
485 s = XSCREEN (XCONS (tail)->car);
486 if (s->visible)
8de2d90b
JB
487 /* Redraw its windows. */
488 redisplay_windows (SCREEN_ROOT_WINDOW (s));
a2889657
JB
489 }
490#else
491 redisplay_windows (SCREEN_ROOT_WINDOW (s));
492#endif /* not MULTI_SCREEN */
493 }
494 else if (SCREEN_VISIBLE_P (selected_screen))
495 {
496 redisplay_window (selected_window, 1);
497 if (XFASTINT (w->width) != SCREEN_WIDTH (selected_screen))
498 preserve_other_columns (w);
499 }
500
501update:
502 /* Prevent various kinds of signals during display update.
503 stdio is not robust about handling signals,
504 which can cause an apparent I/O error. */
505 if (interrupt_input)
506 unrequest_sigio ();
507 stop_polling ();
508
509#ifdef MULTI_SCREEN
510 if (all_windows)
511 {
512 Lisp_Object tail;
513
514 pause = 0;
515
516 for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr)
517 {
518 SCREEN_PTR s;
519
520 if (XTYPE (XCONS (tail)->car) != Lisp_Screen)
521 continue;
522
523 s = XSCREEN (XCONS (tail)->car);
524 if (s->visible)
525 {
8de2d90b 526 pause |= update_screen (s, 0, 0);
a2889657
JB
527 if (!pause)
528 mark_window_display_accurate (s->root_window, 1);
529 }
530 }
531 }
532 else
533#endif /* MULTI_SCREEN */
6e8290aa
JB
534 {
535 if (SCREEN_VISIBLE_P (selected_screen))
536 pause = update_screen (selected_screen, 0, 0);
537#ifdef MULTI_SCREEN
8de2d90b
JB
538 /* We may have called echo_area_display at the top of this
539 function. If the echo area is on another screen, that may
540 have put text on a screen other than the selected one, so the
541 above call to update_screen would not have caught it. Catch
542 it here. */
543 {
544 SCREEN_PTR mini_screen =
545 XSCREEN (WINDOW_SCREEN (XWINDOW (minibuf_window)));
546
547 if (mini_screen != selected_screen)
548 pause |= update_screen (mini_screen, 0, 0);
549 }
6e8290aa
JB
550#endif
551 }
a2889657
JB
552
553 /* If screen does not match, prevent doing single-line-update next time.
554 Also, don't forget to check every line to update the arrow. */
555 if (pause)
556 {
557 this_line_bufpos = 0;
265a9e55 558 if (!NILP (last_arrow_position))
a2889657
JB
559 {
560 last_arrow_position = Qt;
561 last_arrow_string = Qt;
562 }
563 /* If we pause after scrolling, some lines in current_screen
564 may be null, so preserve_other_columns won't be able to
565 preserve all the vertical-bar separators. So, avoid using it
566 in that case. */
567 if (XFASTINT (w->width) != SCREEN_WIDTH (selected_screen))
568 update_mode_lines = 1;
569 }
570
571 /* Now text on screen agrees with windows, so
572 put info into the windows for partial redisplay to follow */
573
574 if (!pause)
575 {
576 register struct buffer *b = XBUFFER (w->buffer);
577
578 blank_end_of_window = 0;
579 clip_changed = 0;
580 unchanged_modified = BUF_MODIFF (b);
581 beg_unchanged = BUF_GPT (b) - BUF_BEG (b);
582 end_unchanged = BUF_Z (b) - BUF_GPT (b);
583
584 XFASTINT (w->last_point) = BUF_PT (b);
585 XFASTINT (w->last_point_x) = SCREEN_CURSOR_X (selected_screen);
586 XFASTINT (w->last_point_y) = SCREEN_CURSOR_Y (selected_screen);
587
588 if (all_windows)
589 mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 1);
590 else
591 {
592 w->update_mode_line = Qnil;
593 XFASTINT (w->last_modified) = BUF_MODIFF (b);
594 w->window_end_valid = Qt;
595 last_arrow_position = Voverlay_arrow_position;
596 last_arrow_string = Voverlay_arrow_string;
597 }
598 update_mode_lines = 0;
599 windows_or_buffers_changed = 0;
600 }
601
602 /* Start SIGIO interrupts coming again.
603 Having them off during the code above
604 makes it less likely one will discard output,
605 but not impossible, since there might be stuff
606 in the system buffer here.
607 But it is much hairier to try to do anything about that. */
608
609 if (interrupt_input)
610 request_sigio ();
611 start_polling ();
612
613 /* Change screen size now if a change is pending. */
614 do_pending_window_change ();
615}
616
617/* Redisplay, but leave alone any recent echo area message
618 unless another message has been requested in its place.
619
620 This is useful in situations where you need to redisplay but no
621 user action has occurred, making it inappropriate for the message
622 area to be cleared. See tracking_off and
623 wait_reading_process_input for examples of these situations. */
624
625redisplay_preserve_echo_area ()
626{
627 if (echo_area_glyphs == 0 && previous_echo_glyphs != 0)
628 {
629 echo_area_glyphs = previous_echo_glyphs;
630 redisplay ();
631 echo_area_glyphs = 0;
632 }
633 else
634 redisplay ();
635}
636
637void
638mark_window_display_accurate (window, flag)
639 Lisp_Object window;
640 int flag;
641{
642 register struct window *w;
643
265a9e55 644 for (;!NILP (window); window = w->next)
a2889657
JB
645 {
646 w = XWINDOW (window);
647
265a9e55 648 if (!NILP (w->buffer))
a2889657
JB
649 XFASTINT (w->last_modified)
650 = !flag ? 0
651 : XBUFFER (w->buffer) == current_buffer
652 ? MODIFF : BUF_MODIFF (XBUFFER (w->buffer));
653 w->window_end_valid = Qt;
654 w->update_mode_line = Qnil;
655
265a9e55 656 if (!NILP (w->vchild))
a2889657 657 mark_window_display_accurate (w->vchild, flag);
265a9e55 658 if (!NILP (w->hchild))
a2889657
JB
659 mark_window_display_accurate (w->hchild, flag);
660 }
661
662 if (flag)
663 {
664 last_arrow_position = Voverlay_arrow_position;
665 last_arrow_string = Voverlay_arrow_string;
666 }
667 else
668 {
669 /* t is unequal to any useful value of Voverlay_arrow_... */
670 last_arrow_position = Qt;
671 last_arrow_string = Qt;
672 }
673}
674\f
675int do_id = 1;
676
677static void
678redisplay_windows (window)
679 Lisp_Object window;
680{
265a9e55 681 for (; !NILP (window); window = XWINDOW (window)->next)
a2889657
JB
682 redisplay_window (window, 0);
683}
684
685static void
686redisplay_window (window, just_this_one)
687 Lisp_Object window;
688 int just_this_one;
689{
690 register struct window *w = XWINDOW (window);
691 SCREEN_PTR s = XSCREEN (w->screen);
692 int height;
693 register int lpoint = point;
694 struct buffer *old = current_buffer;
695 register int width = XFASTINT (w->width) - 1
696 - (XFASTINT (w->width) + XFASTINT (w->left)
697 != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w))));
698 register int startp;
699 register int hscroll = XINT (w->hscroll);
700 struct position pos;
701 int opoint;
702 int tem;
703 int window_needs_modeline;
704
705 if (SCREEN_HEIGHT (s) == 0) abort (); /* Some bug zeros some core */
706
707 /* If this is a combination window, do its children; that's all. */
708
265a9e55 709 if (!NILP (w->vchild))
a2889657
JB
710 {
711 redisplay_windows (w->vchild);
712 return;
713 }
265a9e55 714 if (!NILP (w->hchild))
a2889657
JB
715 {
716 redisplay_windows (w->hchild);
717 return;
718 }
265a9e55 719 if (NILP (w->buffer))
a2889657 720 abort ();
8de2d90b
JB
721
722 height = window_internal_height (w);
723
724 if (MINI_WINDOW_P (w))
725 {
726 if (w == XWINDOW (minibuf_window))
727 {
728 if (echo_area_glyphs)
729 /* We've already displayed the echo area glyphs, if any. */
730 return;
731 }
732 else
733 {
734 /* This is a minibuffer, but it's not the currently active one, so
735 clear it. */
736 int vpos = XFASTINT (XWINDOW (SCREEN_MINIBUF_WINDOW (s))->top);
737 int i;
738
739 for (i = 0; i < height; i++)
740 {
741 get_display_line (s, vpos + i, 0);
742 display_string (w, vpos + i, "", 0, 0, 0, width);
743 }
744
745 return;
746 }
747 }
a2889657
JB
748
749 if (update_mode_lines)
750 w->update_mode_line = Qt;
751
752 /* Otherwise set up data on this window; select its buffer and point value */
753
a2889657
JB
754 current_buffer = XBUFFER (w->buffer);
755 opoint = point;
756
757 /* Count number of windows showing the selected buffer. */
758
759 if (!just_this_one
760 && current_buffer == XBUFFER (XWINDOW (selected_window)->buffer))
761 buffer_shared++;
762
763 /* POINT refers normally to the selected window.
764 For any other window, set up appropriate value. */
765
766 if (!EQ (window, selected_window))
767 {
768 SET_PT (marker_position (w->pointm));
769 if (point < BEGV)
770 {
265a9e55 771 SET_PT (BEGV);
a2889657
JB
772 Fset_marker (w->pointm, make_number (point), Qnil);
773 }
774 else if (point > (ZV - 1))
775 {
265a9e55 776 SET_PT (ZV);
a2889657
JB
777 Fset_marker (w->pointm, make_number (point), Qnil);
778 }
779 }
780
781 /* If window-start is screwed up, choose a new one. */
a2889657
JB
782 if (XMARKER (w->start)->buffer != current_buffer)
783 goto recenter;
784
785 startp = marker_position (w->start);
786
8de2d90b
JB
787 /* Handle case where place to start displaying has been specified,
788 unless the specified location is outside the visible range. */
265a9e55 789 if (!NILP (w->force_start))
a2889657
JB
790 {
791 w->update_mode_line = Qt;
792 w->force_start = Qnil;
793 XFASTINT (w->last_modified) = 0;
8de2d90b
JB
794 if (startp < BEGV) startp = BEGV;
795 if (startp > ZV) startp = ZV;
a2889657
JB
796 try_window (window, startp);
797 if (cursor_vpos < 0)
798 {
799 /* If point does not appear, move point so it does appear */
800 pos = *compute_motion (startp, 0,
801 ((EQ (window, minibuf_window) && startp == 1)
802 ? minibuf_prompt_width : 0)
803 +
804 (hscroll ? 1 - hscroll : 0),
805 ZV, height / 2,
806 - (1 << (SHORTBITS - 1)),
807 width, hscroll, pos_tab_offset (w, startp));
808 SET_PT (pos.bufpos);
809 if (w != XWINDOW (SCREEN_SELECTED_WINDOW (s)))
810 Fset_marker (w->pointm, make_number (point), Qnil);
811 else
812 {
813 lpoint = point;
814 SCREEN_CURSOR_X (s) = max (0, pos.hpos) + XFASTINT (w->left);
815 SCREEN_CURSOR_Y (s) = pos.vpos + XFASTINT (w->top);
816 }
817 }
818 goto done;
819 }
820
821 /* Handle case where text has not changed, only point,
822 and it has not moved off the screen */
823
824 /* This code is not used for minibuffer for the sake of
825 the case of redisplaying to replace an echo area message;
826 since in that case the minibuffer contents per se are usually unchanged.
827 This code is of no real use in the minibuffer since
828 the handling of this_line_bufpos, etc.,
829 in redisplay handles the same cases. */
830
831 if (XFASTINT (w->last_modified) >= MODIFF
832 && point >= startp && !clip_changed
833 && (just_this_one || XFASTINT (w->width) == SCREEN_WIDTH (s))
834 && !EQ (window, minibuf_window))
835 {
836 pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
837 point, height + 1, 10000, width, hscroll,
838 pos_tab_offset (w, startp));
839
840 if (pos.vpos < height)
841 {
842 /* Ok, point is still on screen */
843 if (w == XWINDOW (SCREEN_SELECTED_WINDOW (s)))
844 {
845 /* These variables are supposed to be origin 1 */
846 SCREEN_CURSOR_X (s) = max (0, pos.hpos) + XFASTINT (w->left);
847 SCREEN_CURSOR_Y (s) = pos.vpos + XFASTINT (w->top);
848 }
849 /* This doesn't do the trick, because if a window to the right of
850 this one must be redisplayed, this does nothing because there
851 is nothing in DesiredScreen yet, and then the other window is
852 redisplayed, making likes that are empty in this window's columns.
853 if (XFASTINT (w->width) != SCREEN_WIDTH (s))
854 preserve_my_columns (w);
855 */
856 goto done;
857 }
858 /* Don't bother trying redisplay with same start;
859 we already know it will lose */
860 }
861 /* If current starting point was originally the beginning of a line
862 but no longer is, find a new starting point. */
265a9e55 863 else if (!NILP (w->start_at_line_beg)
a2889657
JB
864 && !(startp == BEGV
865 || FETCH_CHAR (startp - 1) == '\n'))
866 {
867 goto recenter;
868 }
869 else if (just_this_one && !MINI_WINDOW_P (w)
870 && point >= startp
871 && XFASTINT (w->last_modified)
872 && ! EQ (w->window_end_valid, Qnil)
873 && do_id && !clip_changed
874 && !blank_end_of_window
875 && XFASTINT (w->width) == SCREEN_WIDTH (s)
876 && EQ (last_arrow_position, Voverlay_arrow_position)
877 && EQ (last_arrow_string, Voverlay_arrow_string)
878 && (tem = try_window_id (SCREEN_SELECTED_WINDOW (s)))
879 && tem != -2)
880 {
881 /* tem > 0 means success. tem == -1 means choose new start.
882 tem == -2 means try again with same start,
883 and nothing but whitespace follows the changed stuff.
884 tem == 0 means try again with same start. */
885 if (tem > 0)
886 goto done;
887 }
888 else if (startp >= BEGV && startp <= ZV
889 /* Avoid starting display at end of buffer! */
8de2d90b 890 && (startp < ZV || startp == BEGV
a2889657
JB
891 || (XFASTINT (w->last_modified) >= MODIFF)))
892 {
893 /* Try to redisplay starting at same place as before */
894 /* If point has not moved off screen, accept the results */
895 try_window (window, startp);
896 if (cursor_vpos >= 0)
897 goto done;
898 else
899 cancel_my_columns (w);
900 }
901
902 XFASTINT (w->last_modified) = 0;
903 w->update_mode_line = Qt;
904
905 /* Try to scroll by specified few lines */
906
907 if (scroll_step && !clip_changed)
908 {
909 if (point > startp)
910 {
911 pos = *vmotion (Z - XFASTINT (w->window_end_pos),
912 scroll_step, width, hscroll, window);
913 if (pos.vpos >= height)
914 goto scroll_fail;
915 }
916
917 pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step,
918 width, hscroll, window);
919
920 if (point >= pos.bufpos)
921 {
922 try_window (window, pos.bufpos);
923 if (cursor_vpos >= 0)
924 goto done;
925 else
926 cancel_my_columns (w);
927 }
928 scroll_fail: ;
929 }
930
931 /* Finally, just choose place to start which centers point */
932
933recenter:
934 pos = *vmotion (point, - height / 2, width, hscroll, window);
935 try_window (window, pos.bufpos);
936
937 startp = marker_position (w->start);
938 w->start_at_line_beg =
939 (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
940
941done:
942 /* If window not full width, must redo its mode line
943 if the window to its side is being redone */
265a9e55 944 if ((!NILP (w->update_mode_line)
a2889657
JB
945 || (!just_this_one && width < SCREEN_WIDTH (s) - 1))
946 && height != XFASTINT (w->height))
947 display_mode_line (w);
948
949 SET_PT (opoint);
950 current_buffer = old;
951 SET_PT (lpoint);
952}
953\f
954/* Do full redisplay on one window, starting at position `pos'. */
955
956static void
957try_window (window, pos)
958 Lisp_Object window;
959 register int pos;
960{
961 register struct window *w = XWINDOW (window);
962 register int height = window_internal_height (w);
963 register int vpos = XFASTINT (w->top);
964 register int last_text_vpos = vpos;
965 int tab_offset = pos_tab_offset (w, pos);
966 SCREEN_PTR s = XSCREEN (w->screen);
967 int width = XFASTINT (w->width) - 1
968 - (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s));
969 struct position val;
970
971 Fset_marker (w->start, make_number (pos), Qnil);
972 cursor_vpos = -1;
973 overlay_arrow_seen = 0;
974 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
975
976 while (--height >= 0)
977 {
978 val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
979 tab_offset += width;
980 if (val.vpos) tab_offset = 0;
981 vpos++;
982 if (pos != val.bufpos)
983 last_text_vpos
984 /* Next line, unless prev line ended in end of buffer with no cr */
985 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
986 pos = val.bufpos;
987 }
988
989 /* If last line is continued in middle of character,
990 include the split character in the text considered on the screen */
991 if (val.hpos < (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
992 pos++;
993
994 /* If bottom just moved off end of screen, change mode line percentage. */
995 if (XFASTINT (w->window_end_pos) == 0
996 && Z != pos)
997 w->update_mode_line = Qt;
998
999 /* Say where last char on screen will be, once redisplay is finished. */
1000 XFASTINT (w->window_end_pos) = Z - pos;
1001 XFASTINT (w->window_end_vpos) = last_text_vpos - XFASTINT (w->top);
1002 /* But that is not valid info until redisplay finishes. */
1003 w->window_end_valid = Qnil;
1004}
1005\f
1006/* Try to redisplay when buffer is modified locally,
1007 computing insert/delete line to preserve text outside
1008 the bounds of the changes.
1009 Return 1 if successful, 0 if if cannot tell what to do,
1010 or -1 to tell caller to find a new window start,
1011 or -2 to tell caller to do normal redisplay with same window start. */
1012
1013static int
1014try_window_id (window)
1015 Lisp_Object window;
1016{
1017 int pos;
1018 register struct window *w = XWINDOW (window);
1019 register int height = window_internal_height (w);
1020 SCREEN_PTR s = XSCREEN (w->screen);
1021 int top = XFASTINT (w->top);
1022 int start = marker_position (w->start);
1023 int width = XFASTINT (w->width) - 1
1024 - (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s));
1025 int hscroll = XINT (w->hscroll);
1026 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
1027 register int vpos;
1028 register int i, tem;
1029 int last_text_vpos = 0;
1030 int stop_vpos;
1031
1032 struct position val, bp, ep, xp, pp;
1033 int scroll_amount = 0;
1034 int delta;
1035 int tab_offset, epto;
1036
1037 if (GPT - BEG < beg_unchanged)
1038 beg_unchanged = GPT - BEG;
1039 if (Z - GPT < end_unchanged)
1040 end_unchanged = Z - GPT;
1041
1042 if (beg_unchanged + 1 < start)
1043 return 0; /* Give up if changes go above top of window */
1044
1045 /* Find position before which nothing is changed. */
1046 bp = *compute_motion (start, 0, lmargin,
f7be7f78 1047 beg_unchanged + 1, height + 1, 0, width, hscroll,
a2889657
JB
1048 pos_tab_offset (w, start));
1049 if (bp.vpos >= height)
6e8290aa
JB
1050 {
1051 if (point < bp.bufpos && !bp.contin)
1052 {
1053 /* All changes are below the screen, and point is on the screen.
1054 We don't need to change the screen at all.
1055 But we need to update window_end_pos to account for
1056 any change in buffer size. */
f7be7f78
JB
1057 bp = *compute_motion (start, 0, lmargin,
1058 Z, height, 0,
1059 width, hscroll, pos_tab_offset (w, start));
6e8290aa
JB
1060 XFASTINT (w->window_end_vpos) = height;
1061 XFASTINT (w->window_end_pos) = Z - bp.bufpos;
1062 return 1;
1063 }
1064 return 0;
1065 }
a2889657
JB
1066
1067 vpos = bp.vpos;
1068
1069 /* Find beginning of that screen line. Must display from there. */
1070 bp = *vmotion (bp.bufpos, 0, width, hscroll, window);
1071
1072 pos = bp.bufpos;
1073 val.hpos = lmargin;
1074 if (pos < start)
1075 return -1;
1076
1077 /* If about to start displaying at the beginning of a continuation line,
1078 really start with previous screen line, in case it was not
1079 continued when last redisplayed */
05ba02eb
JB
1080 if ((bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0)
1081 ||
1082 /* Likewise if we have to worry about selective display. */
1083 (XTYPE (current_buffer->selective_display) == Lisp_Int
1084 && XINT (current_buffer->selective_display) > 0
1085 && bp.bufpos - 1 == beg_unchanged && vpos > 0))
a2889657
JB
1086 {
1087 bp = *vmotion (bp.bufpos, -1, width, hscroll, window);
1088 --vpos;
1089 pos = bp.bufpos;
1090 }
1091
1092 if (bp.contin && bp.hpos != lmargin)
1093 {
1094 val.hpos = bp.prevhpos - width + lmargin;
1095 pos--;
1096 }
1097
1098 bp.vpos = vpos;
1099
1100 /* Find first visible newline after which no more is changed. */
1101 tem = find_next_newline (Z - max (end_unchanged, Z - ZV), 1);
1102 if (XTYPE (current_buffer->selective_display) == Lisp_Int
1103 && XINT (current_buffer->selective_display) > 0)
1104 while (tem < ZV - 1
1105 && (position_indentation (tem)
1106 >= XINT (current_buffer->selective_display)))
1107 tem = find_next_newline (tem, 1);
1108
1109 /* Compute the cursor position after that newline. */
1110 ep = *compute_motion (pos, vpos, val.hpos, tem,
1111 height, - (1 << (SHORTBITS - 1)),
1112 width, hscroll, pos_tab_offset (w, bp.bufpos));
1113
1114 /* If changes reach past the text available on the screen,
1115 just display rest of screen. */
1116 if (ep.bufpos > Z - XFASTINT (w->window_end_pos))
1117 stop_vpos = height;
1118 else
1119 stop_vpos = ep.vpos;
1120
1121 /* If no newline before ep, the line ep is on includes some changes
1122 that must be displayed. Make sure we don't stop before it. */
1123 /* Also, if changes reach all the way until ep.bufpos,
1124 it is possible that something was deleted after the
1125 newline before it, so the following line must be redrawn. */
1126 if (stop_vpos == ep.vpos
1127 && (ep.bufpos == BEGV
1128 || FETCH_CHAR (ep.bufpos - 1) != '\n'
1129 || ep.bufpos == Z - end_unchanged))
1130 stop_vpos = ep.vpos + 1;
1131
1132 cursor_vpos = -1;
1133 overlay_arrow_seen = 0;
1134
1135 /* If changes do not reach to bottom of window,
1136 figure out how much to scroll the rest of the window */
1137 if (stop_vpos < height)
1138 {
1139 /* Now determine how far up or down the rest of the window has moved */
1140 epto = pos_tab_offset (w, ep.bufpos);
1141 xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
1142 Z - XFASTINT (w->window_end_pos),
1143 10000, 0, width, hscroll, epto);
1144 scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
1145
1146 /* Is everything on screen below the changes whitespace?
1147 If so, no scrolling is really necessary. */
1148 for (i = ep.bufpos; i < xp.bufpos; i++)
1149 {
1150 tem = FETCH_CHAR (i);
1151 if (tem != ' ' && tem != '\n' && tem != '\t')
1152 break;
1153 }
1154 if (i == xp.bufpos)
1155 return -2;
1156
1157 XFASTINT (w->window_end_vpos) += scroll_amount;
1158
1159 /* Before doing any scrolling, verify that point will be on screen. */
1160 if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height))
1161 {
1162 if (point <= xp.bufpos)
1163 {
1164 pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
1165 point, height, - (1 << (SHORTBITS - 1)),
1166 width, hscroll, epto);
1167 }
1168 else
1169 {
1170 pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
1171 point, height, - (1 << (SHORTBITS - 1)),
1172 width, hscroll, pos_tab_offset (w, xp.bufpos));
1173 }
1174 if (pp.bufpos < point || pp.vpos == height)
1175 return 0;
1176 cursor_vpos = pp.vpos + top;
1177 cursor_hpos = pp.hpos + XFASTINT (w->left);
1178 }
1179
1180 if (stop_vpos - scroll_amount >= height
1181 || ep.bufpos == xp.bufpos)
1182 {
1183 if (scroll_amount < 0)
1184 stop_vpos -= scroll_amount;
1185 scroll_amount = 0;
1186 /* In this path, we have altered window_end_vpos
1187 and not left it negative.
1188 We must make sure that, in case display is preempted
1189 before the screen changes to reflect what we do here,
1190 further updates will not come to try_window_id
1191 and assume the screen and window_end_vpos match. */
1192 blank_end_of_window = 1;
1193 }
1194 else if (!scroll_amount)
1195 {}
1196 else if (bp.bufpos == Z - end_unchanged)
1197 {
1198 /* If reprinting everything is nearly as fast as scrolling,
1199 don't bother scrolling. Can happen if lines are short. */
1200 if (scroll_cost (s, bp.vpos + top - scroll_amount,
1201 top + height - max (0, scroll_amount),
1202 scroll_amount)
1203 > xp.bufpos - bp.bufpos - 20)
1204 /* Return "try normal display with same window-start."
1205 Too bad we can't prevent further scroll-thinking. */
1206 return -2;
1207 /* If pure deletion, scroll up as many lines as possible.
1208 In common case of killing a line, this can save the
1209 following line from being overwritten by scrolling
1210 and therefore having to be redrawn. */
1211 tem = scroll_screen_lines (s, bp.vpos + top - scroll_amount,
1212 top + height - max (0, scroll_amount),
1213 scroll_amount);
1214 if (!tem) stop_vpos = height;
1215 }
1216 else if (scroll_amount)
1217 {
1218 /* If reprinting everything is nearly as fast as scrolling,
1219 don't bother scrolling. Can happen if lines are short. */
1220 /* Note that if scroll_amount > 0, xp.bufpos - bp.bufpos is an
1221 overestimate of cost of reprinting, since xp.bufpos
1222 would end up below the bottom of the window. */
1223 if (scroll_cost (s, ep.vpos + top - scroll_amount,
1224 top + height - max (0, scroll_amount),
1225 scroll_amount)
1226 > xp.bufpos - ep.bufpos - 20)
1227 /* Return "try normal display with same window-start."
1228 Too bad we can't prevent further scroll-thinking. */
1229 return -2;
1230 tem = scroll_screen_lines (s, ep.vpos + top - scroll_amount,
1231 top + height - max (0, scroll_amount),
1232 scroll_amount);
1233 if (!tem) stop_vpos = height;
1234 }
1235 }
1236
1237 /* In any case, do not display past bottom of window */
1238 if (stop_vpos >= height)
1239 {
1240 stop_vpos = height;
1241 scroll_amount = 0;
1242 }
1243
1244 /* Handle case where pos is before w->start --
1245 can happen if part of line had been clipped and is not clipped now */
1246 if (vpos == 0 && pos < marker_position (w->start))
1247 Fset_marker (w->start, make_number (pos), Qnil);
1248
1249 /* Redisplay the lines where the text was changed */
1250 last_text_vpos = vpos;
1251 tab_offset = pos_tab_offset (w, pos);
1252 /* If we are starting display in mid-character, correct tab_offset
1253 to account for passing the line that that character really starts in. */
1254 if (val.hpos < lmargin)
1255 tab_offset += width;
1256 while (vpos < stop_vpos)
1257 {
1258 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
1259 tab_offset += width;
1260 if (val.vpos) tab_offset = 0;
1261 if (pos != val.bufpos)
1262 last_text_vpos
1263 /* Next line, unless prev line ended in end of buffer with no cr */
1264 = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
1265 pos = val.bufpos;
1266 }
1267
1268 /* There are two cases:
1269 1) we have displayed down to the bottom of the window
1270 2) we have scrolled lines below stop_vpos by scroll_amount */
1271
1272 if (vpos == height)
1273 {
1274 /* If last line is continued in middle of character,
1275 include the split character in the text considered on the screen */
1276 if (val.hpos < lmargin)
1277 val.bufpos++;
1278 XFASTINT (w->window_end_vpos) = last_text_vpos;
1279 XFASTINT (w->window_end_pos) = Z - val.bufpos;
1280 }
1281
1282 /* If scrolling made blank lines at window bottom,
1283 redisplay to fill those lines */
1284 if (scroll_amount < 0)
1285 {
1286 /* Don't consider these lines for general-purpose scrolling.
1287 That will save time in the scrolling computation. */
1288 SCREEN_SCROLL_BOTTOM_VPOS (s) = xp.vpos;
1289 vpos = xp.vpos;
1290 pos = xp.bufpos;
1291 val.hpos = lmargin;
1292 if (pos == ZV)
1293 vpos = height + scroll_amount;
1294 else if (xp.contin && xp.hpos != lmargin)
1295 {
1296 val.hpos = xp.prevhpos - width + lmargin;
1297 pos--;
1298 }
1299
1300 blank_end_of_window = 1;
1301 tab_offset = pos_tab_offset (w, pos);
1302 /* If we are starting display in mid-character, correct tab_offset
1303 to account for passing the line that that character starts in. */
1304 if (val.hpos < lmargin)
1305 tab_offset += width;
1306
1307 while (vpos < height)
1308 {
1309 val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
1310 tab_offset += width;
1311 if (val.vpos) tab_offset = 0;
1312 pos = val.bufpos;
1313 }
1314
1315 /* Here is a case where display_text_line sets cursor_vpos wrong.
1316 Make it be fixed up, below. */
1317 if (xp.bufpos == ZV
1318 && xp.bufpos == point)
1319 cursor_vpos = -1;
1320 }
1321
1322 /* If bottom just moved off end of screen, change mode line percentage. */
1323 if (XFASTINT (w->window_end_pos) == 0
1324 && Z != val.bufpos)
1325 w->update_mode_line = Qt;
1326
1327 /* Attempt to adjust end-of-text positions to new bottom line */
1328 if (scroll_amount)
1329 {
1330 delta = height - xp.vpos;
1331 if (delta < 0
1332 || (delta > 0 && xp.bufpos <= ZV)
1333 || (delta == 0 && xp.hpos))
1334 {
1335 val = *vmotion (Z - XFASTINT (w->window_end_pos),
1336 delta, width, hscroll, window);
1337 XFASTINT (w->window_end_pos) = Z - val.bufpos;
1338 XFASTINT (w->window_end_vpos) += val.vpos;
1339 }
1340 }
1341
1342 w->window_end_valid = Qnil;
1343
1344 /* If point was not in a line that was displayed, find it */
1345 if (cursor_vpos < 0)
1346 {
1347 val = *compute_motion (start, 0, lmargin, point, 10000, 10000,
1348 width, hscroll, pos_tab_offset (w, start));
1349 /* Admit failure if point is off screen now */
1350 if (val.vpos >= height)
1351 {
1352 for (vpos = 0; vpos < height; vpos++)
1353 cancel_line (vpos + top, s);
1354 return 0;
1355 }
1356 cursor_vpos = val.vpos + top;
1357 cursor_hpos = val.hpos + XFASTINT (w->left);
1358 }
1359
1360 SCREEN_CURSOR_X (s) = max (0, cursor_hpos);
1361 SCREEN_CURSOR_Y (s) = cursor_vpos;
1362
1363 if (debug_end_pos)
1364 {
1365 val = *compute_motion (start, 0, lmargin, ZV,
1366 height, - (1 << (SHORTBITS - 1)),
1367 width, hscroll, pos_tab_offset (w, start));
1368 if (val.vpos != XFASTINT (w->window_end_vpos))
1369 abort ();
1370 if (XFASTINT (w->window_end_pos)
1371 != Z - val.bufpos)
1372 abort ();
1373 }
1374
1375 return 1;
1376}
1377\f
f7430cb6
JB
1378/* Copy glyphs from the rope FROM to T.
1379 But don't actually copy the parts that would come in before S.
a2889657
JB
1380 Value is T, advanced past the copied data.
1381
1382 Characters in FROM are grouped into units of `sizeof GLYPH' chars;
1383 any extra chars at the end of FROM are ignored. */
1384
1385GLYPH *
1386copy_rope (t, s, from)
1387 register GLYPH *t; /* Copy to here. */
1388 register GLYPH *s; /* Starting point. */
1389 Lisp_Object from; /* Data to copy; known to be a string. */
1390{
1391 register int n = XSTRING (from)->size / sizeof (GLYPH);
1392 register GLYPH *f = (GLYPH *) XSTRING (from)->data;
1393
1394 while (n--)
1395 {
1396 if (t >= s) *t = *f;
1397 ++t;
1398 ++f;
1399 }
1400 return t;
1401}
1402\f
1403/* Display one line of window w, starting at position START in W's buffer.
1404 Display starting at horizontal position HPOS, which is normally zero
1405 or negative. A negative value causes output up to hpos = 0 to be discarded.
1406 This is done for negative hscroll, or when this is a continuation line
1407 and the continuation occurred in the middle of a multi-column character.
1408
1409 TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
1410
1411 Display on position VPOS on the screen. (origin 0).
1412
1413 Returns a STRUCT POSITION giving character to start next line with
1414 and where to display it, including a zero or negative hpos.
1415 The vpos field is not really a vpos; it is 1 unless the line is continued */
1416
1417struct position val_display_text_line;
1418
1419static struct position *
1420display_text_line (w, start, vpos, hpos, taboffset)
1421 struct window *w;
1422 int start;
1423 int vpos;
1424 int hpos;
1425 int taboffset;
1426{
1427 register int pos = start;
1428 register int c;
1429 register GLYPH *p1;
1430 int end;
1431 register int pause;
1432 register unsigned char *p;
1433 GLYPH *endp;
1434 register GLYPH *startp;
1435 register GLYPH *p1prev;
1436 SCREEN_PTR s = XSCREEN (w->screen);
1437 int tab_width = XINT (current_buffer->tab_width);
265a9e55 1438 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
a2889657
JB
1439 int width = XFASTINT (w->width) - 1
1440 - (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s));
1441 struct position val;
1442 int lastpos;
1443 int invis;
1444 int hscroll = XINT (w->hscroll);
1445 int truncate = hscroll
1446 || (truncate_partial_width_windows
1447 && XFASTINT (w->width) < SCREEN_WIDTH (s))
265a9e55 1448 || !NILP (current_buffer->truncate_lines);
a2889657
JB
1449 int selective
1450 = XTYPE (current_buffer->selective_display) == Lisp_Int
1451 ? XINT (current_buffer->selective_display)
265a9e55 1452 : !NILP (current_buffer->selective_display) ? -1 : 0;
a2889657 1453#ifndef old
265a9e55 1454 int selective_e = selective && !NILP (current_buffer->selective_display_ellipses);
a2889657
JB
1455#endif
1456 register struct screen_glyphs *desired_glyphs = SCREEN_DESIRED_GLYPHS (s);
1457 register struct Lisp_Vector *dp = window_display_table (w);
1458 int selective_rlen
1459 = (selective && dp && XTYPE (DISP_INVIS_ROPE (dp)) == Lisp_String
1460 ? XSTRING (DISP_INVIS_ROPE (dp))->size / sizeof (GLYPH) : 0);
1461 GLYPH truncator = (dp == 0 || XTYPE (DISP_TRUNC_GLYPH (dp)) != Lisp_Int
1462 ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
1463 GLYPH continuer = (dp == 0 || XTYPE (DISP_CONTINUE_GLYPH (dp)) != Lisp_Int
1464 ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
1465
1466 hpos += XFASTINT (w->left);
1467 get_display_line (s, vpos, XFASTINT (w->left));
1468 if (tab_width <= 0 || tab_width > 20) tab_width = 8;
1469
1470 if (MINI_WINDOW_P (w) && start == 1
1471 && vpos == XFASTINT (w->top))
1472 {
1473 if (minibuf_prompt)
1474 hpos = display_string (w, vpos, minibuf_prompt, hpos,
1475 (!truncate ? continuer : truncator),
1476 -1, -1);
1477 minibuf_prompt_width = hpos;
1478 }
1479
1480 desired_glyphs->bufp[vpos] = pos;
1481 p1 = desired_glyphs->glyphs[vpos] + hpos;
1482 end = ZV;
1483 startp = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
1484 endp = startp + width;
1485
1486 /* Loop generating characters.
1487 Stop at end of buffer, before newline,
1488 or if reach or pass continuation column. */
1489
1490 pause = pos;
1491 while (p1 < endp)
1492 {
1493 p1prev = p1;
1494 if (pos == pause)
1495 {
1496 if (pos == end)
1497 break;
1498 if (pos == point && cursor_vpos < 0)
1499 {
1500 cursor_vpos = vpos;
1501 cursor_hpos = p1 - startp;
1502 }
1503
1504 pause = end;
1505 if (pos < point && point < pause)
1506 pause = point;
1507 if (pos < GPT && GPT < pause)
1508 pause = GPT;
1509
1510 p = &FETCH_CHAR (pos);
1511 }
1512 c = *p++;
1513 if (c >= 040 && c < 0177
1514 && (dp == 0 || XTYPE (DISP_CHAR_ROPE (dp, c)) != Lisp_String))
1515 {
1516 if (p1 >= startp)
1517 *p1 = c;
1518 p1++;
1519 }
1520 else if (c == '\n')
1521 {
1522 invis = 0;
1523 while (pos < end
1524 && selective > 0
1525 && position_indentation (pos + 1) >= selective)
1526 {
1527 invis = 1;
1528 pos = find_next_newline (pos + 1, 1);
1529 if (FETCH_CHAR (pos - 1) == '\n')
1530 pos--;
1531 }
1532 if (invis && selective_rlen > 0 && p1 >= startp)
1533 {
1534 p1 += selective_rlen;
1535 if (p1 - startp > width)
1536 p1 = endp;
1537 bcopy (XSTRING (DISP_INVIS_ROPE (dp))->data, p1prev,
1538 (p1 - p1prev) * sizeof (GLYPH));
1539 }
1540 break;
1541 }
1542 else if (c == '\t')
1543 {
1544 do
1545 {
1546 if (p1 >= startp && p1 < endp)
1547 *p1 = SPACEGLYPH;
1548 p1++;
1549 }
1550 while ((p1 - startp + taboffset + hscroll - (hscroll > 0))
1551 % tab_width);
1552 }
6e8290aa 1553 else if (c == Ctl ('M') && selective == -1)
a2889657
JB
1554 {
1555 pos = find_next_newline (pos, 1);
1556 if (FETCH_CHAR (pos - 1) == '\n')
1557 pos--;
1558 if (selective_rlen > 0)
1559 {
1560 p1 += selective_rlen;
1561 if (p1 - startp > width)
1562 p1 = endp;
1563 bcopy (XSTRING (DISP_INVIS_ROPE (dp))->data, p1prev,
1564 (p1 - p1prev) * sizeof (GLYPH));
1565 }
1566 break;
1567 }
1568 else if (dp != 0 && XTYPE (DISP_CHAR_ROPE (dp, c)) == Lisp_String)
1569 {
1570 p1 = copy_rope (p1, startp, DISP_CHAR_ROPE (dp, c));
1571 }
1572 else if (c < 0200 && ctl_arrow)
1573 {
1574 if (p1 >= startp)
1575 *p1 = (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
1576 ? XINT (DISP_CTRL_GLYPH (dp)) : '^');
1577 p1++;
6e8290aa 1578 if (p1 >= startp && p1 < endp)
a2889657
JB
1579 *p1 = c ^ 0100;
1580 p1++;
1581 }
1582 else
1583 {
1584 if (p1 >= startp)
1585 *p1 = (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
1586 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\');
1587 p1++;
6e8290aa 1588 if (p1 >= startp && p1 < endp)
a2889657
JB
1589 *p1 = (c >> 6) + '0';
1590 p1++;
6e8290aa 1591 if (p1 >= startp && p1 < endp)
a2889657
JB
1592 *p1 = (7 & (c >> 3)) + '0';
1593 p1++;
6e8290aa 1594 if (p1 >= startp && p1 < endp)
a2889657
JB
1595 *p1 = (7 & c) + '0';
1596 p1++;
1597 }
1598 pos++;
1599 }
1600
1601 val.hpos = - XINT (w->hscroll);
1602 if (val.hpos)
1603 val.hpos++;
1604
1605 val.vpos = 1;
1606
1607 lastpos = pos;
1608
1609 /* Handle continuation in middle of a character */
1610 /* by backing up over it */
1611 if (p1 > endp)
1612 {
1613 /* Start the next line with that same character */
1614 pos--;
1615 /* but at a negative hpos, to skip the columns output on this line. */
1616 val.hpos += p1prev - endp;
1617 /* Keep in this line everything up to the continuation column. */
1618 p1 = endp;
1619 }
1620
1621 /* Finish deciding which character to start the next line on,
1622 and what hpos to start it at.
1623 Also set `lastpos' to the last position which counts as "on this line"
1624 for cursor-positioning. */
1625
1626 if (pos < ZV)
1627 {
1628 if (FETCH_CHAR (pos) == '\n')
1629 /* If stopped due to a newline, start next line after it */
1630 pos++;
1631 else
1632 /* Stopped due to right margin of window */
1633 {
1634 if (truncate)
1635 {
1636 *p1++ = truncator;
1637 /* Truncating => start next line after next newline,
1638 and point is on this line if it is before the newline,
1639 and skip none of first char of next line */
1640 pos = find_next_newline (pos, 1);
1641 val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
1642
1643 lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
1644 }
1645 else
1646 {
1647 *p1++ = continuer;
1648 val.vpos = 0;
1649 lastpos--;
1650 }
1651 }
1652 }
1653
1654 /* If point is at eol or in invisible text at eol,
1655 record its screen location now. */
1656
1657 if (start <= point && point <= lastpos && cursor_vpos < 0)
1658 {
1659 cursor_vpos = vpos;
1660 cursor_hpos = p1 - startp;
1661 }
1662
1663 if (cursor_vpos == vpos)
1664 {
1665 if (cursor_hpos < 0) cursor_hpos = 0;
1666 if (cursor_hpos > width) cursor_hpos = width;
1667 cursor_hpos += XFASTINT (w->left);
1668 if (w == XWINDOW (SCREEN_SELECTED_WINDOW (s)))
1669 {
1670 SCREEN_CURSOR_Y (s) = cursor_vpos;
1671 SCREEN_CURSOR_X (s) = cursor_hpos;
1672
1673 if (w == XWINDOW (selected_window))
1674 {
1675 /* Line is not continued and did not start
1676 in middle of character */
1677 if ((hpos - XFASTINT (w->left)
1678 == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
1679 && val.vpos)
1680 {
1681 this_line_bufpos = start;
1682 this_line_buffer = current_buffer;
1683 this_line_vpos = cursor_vpos;
1684 this_line_start_hpos = hpos;
1685 this_line_endpos = Z - lastpos;
1686 }
1687 else
1688 this_line_bufpos = 0;
1689 }
1690 }
1691 }
1692
1693 /* If hscroll and line not empty, insert truncation-at-left marker */
1694 if (hscroll && lastpos != start)
1695 {
1696 *startp = truncator;
1697 if (p1 <= startp)
1698 p1 = startp + 1;
1699 }
1700
1701 if (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s))
1702 {
1703 endp++;
1704 if (p1 < startp) p1 = startp;
1705 while (p1 < endp) *p1++ = SPACEGLYPH;
1706 *p1++ = '|';
1707 }
1708 desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
1709 p1 - desired_glyphs->glyphs[vpos]);
1710 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
1711
1712 /* If the start of this line is the overlay arrow-position,
1713 then put the arrow string into the display-line. */
1714
1715 if (XTYPE (Voverlay_arrow_position) == Lisp_Marker
1716 && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
1717 && start == marker_position (Voverlay_arrow_position)
1718 && XTYPE (Voverlay_arrow_string) == Lisp_String
1719 && ! overlay_arrow_seen)
1720 {
1721 unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
1722 int i;
1723 int len = XSTRING (Voverlay_arrow_string)->size;
1724
1725 if (len > XFASTINT (w->width) - 1)
1726 len = XFASTINT (w->width) - 1;
1727 for (i = 0; i < len; i++)
1728 startp[i] = p[i];
1729 if (desired_glyphs->used[vpos] <
1730 (len + startp - desired_glyphs->glyphs[vpos]))
1731 desired_glyphs->used[vpos] = len + startp - desired_glyphs->glyphs[vpos];
1732
1733 overlay_arrow_seen = 1;
1734 }
1735
1736 val.bufpos = pos;
1737 val_display_text_line = val;
1738 return &val_display_text_line;
1739}
1740\f
1741/* Display the mode line for window w */
1742
1743static void
1744display_mode_line (w)
1745 struct window *w;
1746{
1747 register int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
1748 register int left = XFASTINT (w->left);
1749 register int right = XFASTINT (w->width) + left;
1750 register SCREEN_PTR s = XSCREEN (WINDOW_SCREEN (w));
1751
1752 get_display_line (s, vpos, left);
1753 display_mode_element (w, vpos, left, 0, right, right,
1754 current_buffer->mode_line_format);
1755 SCREEN_DESIRED_GLYPHS (s)->bufp[vpos] = 0;
1756
1757 /* Make the mode line inverse video if the entire line
1758 is made of mode lines.
1759 I.e. if this window is full width,
1760 or if it is the child of a full width window
1761 (which implies that that window is split side-by-side
1762 and the rest of this line is mode lines of the sibling windows). */
1763 if (XFASTINT (w->width) == SCREEN_WIDTH (s)
1764 || XFASTINT (XWINDOW (w->parent)->width) == SCREEN_WIDTH (s))
e5d77022 1765 SCREEN_DESIRED_GLYPHS (s)->highlight[vpos] = mode_line_inverse_video;
a2889657
JB
1766
1767#ifdef HAVE_X_WINDOWS
1768 /* I'm trying this out because I saw Unimpress use it, but it's
8de2d90b 1769 possible that this may mess adversely with some window managers. jla */
a2889657
JB
1770
1771 if (SCREEN_IS_X (s)
8de2d90b 1772 && ! SCREEN_MINIBUF_ONLY_P (s)
a2889657 1773 && w == XWINDOW (s->selected_window)
265a9e55 1774 && (NILP (Fstring_equal (XBUFFER (w->buffer)->name, s->name))))
a2889657
JB
1775 x_set_name (s, XBUFFER (w->buffer)->name, Qnil);
1776#endif
1777}
1778
1779/* Contribute ELT to the mode line for window W.
1780 How it translates into text depends on its data type.
1781
1782 VPOS is the position of the mode line being displayed.
1783
1784 HPOS is the position (absolute on screen) where this element's text
1785 should start. The output is truncated automatically at the right
1786 edge of window W.
1787
1788 DEPTH is the depth in recursion. It is used to prevent
1789 infinite recursion here.
1790
1791 MINENDCOL is the hpos before which the element may not end.
1792 The element is padded at the right with spaces if nec
1793 to reach this column.
1794
1795 MAXENDCOL is the hpos past which this element may not extend.
1796 If MINENDCOL is > MAXENDCOL, MINENDCOL takes priority.
1797 (This is necessary to make nested padding and truncation work.)
1798
1799 Returns the hpos of the end of the text generated by ELT.
1800 The next element will receive that value as its HPOS arg,
1801 so as to concatenate the elements. */
1802
1803static int
1804display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
1805 struct window *w;
1806 register int vpos, hpos;
1807 int depth;
1808 int minendcol;
1809 register int maxendcol;
1810 register Lisp_Object elt;
1811{
1812 tail_recurse:
1813 if (depth > 10)
1814 goto invalid;
1815
1816 depth++;
1817
1818#ifdef SWITCH_ENUM_BUG
1819 switch ((int) XTYPE (elt))
1820#else
1821 switch (XTYPE (elt))
1822#endif
1823 {
1824 case Lisp_String:
1825 {
1826 /* A string: output it and check for %-constructs within it. */
1827 register unsigned char c;
1828 register unsigned char *this = XSTRING (elt)->data;
1829
1830 while (hpos < maxendcol && *this)
1831 {
1832 unsigned char *last = this;
1833 while ((c = *this++) != '\0' && c != '%')
1834 ;
1835 if (this - 1 != last)
1836 {
1837 register int lim = --this - last + hpos;
1838 hpos = display_string (w, vpos, last, hpos, 0, hpos,
1839 min (lim, maxendcol));
1840 }
1841 else /* c == '%' */
1842 {
1843 register int spec_width = 0;
1844
1845 /* We can't allow -ve args due to the "%-" construct */
1846 /* Argument specifies minwidth but not maxwidth
1847 (maxwidth can be specified by
1848 (<negative-number> . <stuff>) mode-line elements) */
1849
1850 while ((c = *this++) >= '0' && c <= '9')
1851 {
1852 spec_width = spec_width * 10 + (c - '0');
1853 }
1854
1855 spec_width += hpos;
1856 if (spec_width > maxendcol)
1857 spec_width = maxendcol;
1858
1859 if (c == 'M')
1860 hpos = display_mode_element (w, vpos, hpos, depth,
1861 spec_width, maxendcol,
1862 Vglobal_mode_string);
1863 else if (c != 0)
1864 hpos = display_string (w, vpos,
1865 decode_mode_spec (w, c,
1866 maxendcol - hpos),
1867 hpos, 0, spec_width, maxendcol);
1868 }
1869 }
1870 }
1871 break;
1872
1873 case Lisp_Symbol:
1874 /* A symbol: process the value of the symbol recursively
1875 as if it appeared here directly. Avoid error if symbol void.
1876 Special case: if value of symbol is a string, output the string
1877 literally. */
1878 {
1879 register Lisp_Object tem;
1880 tem = Fboundp (elt);
265a9e55 1881 if (!NILP (tem))
a2889657
JB
1882 {
1883 tem = Fsymbol_value (elt);
1884 /* If value is a string, output that string literally:
1885 don't check for % within it. */
1886 if (XTYPE (tem) == Lisp_String)
1887 hpos = display_string (w, vpos, XSTRING (tem)->data,
1888 hpos, 0, minendcol, maxendcol);
1889 /* Give up right away for nil or t. */
1890 else if (!EQ (tem, elt))
1891 { elt = tem; goto tail_recurse; }
1892 }
1893 }
1894 break;
1895
1896 case Lisp_Cons:
1897 {
1898 register Lisp_Object car, tem;
1899
1900 /* A cons cell: three distinct cases.
1901 If first element is a string or a cons, process all the elements
1902 and effectively concatenate them.
1903 If first element is a negative number, truncate displaying cdr to
1904 at most that many characters. If positive, pad (with spaces)
1905 to at least that many characters.
1906 If first element is a symbol, process the cadr or caddr recursively
1907 according to whether the symbol's value is non-nil or nil. */
1908 car = XCONS (elt)->car;
1909 if (XTYPE (car) == Lisp_Symbol)
1910 {
1911 tem = Fboundp (car);
1912 elt = XCONS (elt)->cdr;
1913 if (XTYPE (elt) != Lisp_Cons)
1914 goto invalid;
1915 /* elt is now the cdr, and we know it is a cons cell.
1916 Use its car if CAR has a non-nil value. */
265a9e55 1917 if (!NILP (tem))
a2889657
JB
1918 {
1919 tem = Fsymbol_value (car);
265a9e55 1920 if (!NILP (tem))
a2889657
JB
1921 { elt = XCONS (elt)->car; goto tail_recurse; }
1922 }
1923 /* Symbol's value is nil (or symbol is unbound)
1924 Get the cddr of the original list
1925 and if possible find the caddr and use that. */
1926 elt = XCONS (elt)->cdr;
265a9e55 1927 if (NILP (elt))
a2889657
JB
1928 break;
1929 else if (XTYPE (elt) != Lisp_Cons)
1930 goto invalid;
1931 elt = XCONS (elt)->car;
1932 goto tail_recurse;
1933 }
1934 else if (XTYPE (car) == Lisp_Int)
1935 {
1936 register int lim = XINT (car);
1937 elt = XCONS (elt)->cdr;
1938 if (lim < 0)
1939 /* Negative int means reduce maximum width.
1940 DO NOT change MINENDCOL here!
1941 (20 -10 . foo) should truncate foo to 10 col
1942 and then pad to 20. */
1943 maxendcol = min (maxendcol, hpos - lim);
1944 else if (lim > 0)
1945 {
1946 /* Padding specified. Don't let it be more than
1947 current maximum. */
1948 lim += hpos;
1949 if (lim > maxendcol)
1950 lim = maxendcol;
1951 /* If that's more padding than already wanted, queue it.
1952 But don't reduce padding already specified even if
1953 that is beyond the current truncation point. */
1954 if (lim > minendcol)
1955 minendcol = lim;
1956 }
1957 goto tail_recurse;
1958 }
1959 else if (XTYPE (car) == Lisp_String || XTYPE (car) == Lisp_Cons)
1960 {
1961 register int limit = 50;
1962 /* LIMIT is to protect against circular lists. */
1963 while (XTYPE (elt) == Lisp_Cons && --limit > 0
1964 && hpos < maxendcol)
1965 {
1966 hpos = display_mode_element (w, vpos, hpos, depth,
1967 hpos, maxendcol,
1968 XCONS (elt)->car);
1969 elt = XCONS (elt)->cdr;
1970 }
1971 }
1972 }
1973 break;
1974
1975 default:
1976 invalid:
1977 return (display_string (w, vpos, "*invalid*", hpos, 0,
1978 minendcol, maxendcol));
1979 }
1980
1981 end:
1982 if (minendcol > hpos)
1983 hpos = display_string (w, vpos, "", hpos, 0, minendcol, -1);
1984 return hpos;
1985}
1986\f
1987/* Return a string for the output of a mode line %-spec for window W,
1988 generated by character C and width MAXWIDTH. */
1989
1990static char *
1991decode_mode_spec (w, c, maxwidth)
1992 struct window *w;
1993 register char c;
1994 register int maxwidth;
1995{
1996 Lisp_Object obj = Qnil;
1997 SCREEN_PTR scr = XSCREEN (WINDOW_SCREEN (w));
1998 char *decode_mode_spec_buf = (char *) SCREEN_TEMP_GLYPHS (scr)->total_contents;
1999
2000 if (maxwidth > SCREEN_WIDTH (scr))
2001 maxwidth = SCREEN_WIDTH (scr);
2002
2003 switch (c)
2004 {
2005 case 'b':
2006 obj = current_buffer->name;
2007#if 0
2008 if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
2009 {
2010 bcopy (XSTRING (obj)->data, decode_mode_spec_buf, maxwidth - 1);
2011 decode_mode_spec_buf[maxwidth - 1] = '\\';
2012 decode_mode_spec_buf[maxwidth] = '\0';
2013 return decode_mode_spec_buf;
2014 }
2015#endif
2016 break;
2017
2018 case 'f':
2019 obj = current_buffer->filename;
2020#if 0
265a9e55 2021 if (NILP (obj))
a2889657
JB
2022 return "[none]";
2023 else if (XTYPE (obj) == Lisp_String && XSTRING (obj)->size > maxwidth)
2024 {
2025 bcopy ("...", decode_mode_spec_buf, 3);
2026 bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
2027 decode_mode_spec_buf + 3, maxwidth - 3);
2028 return decode_mode_spec_buf;
2029 }
2030#endif
2031 break;
2032
2033 case 'm':
2034 obj = current_buffer->mode_name;
2035 break;
2036
2037 case 'n':
2038 if (BEGV > BEG || ZV < Z)
2039 return " Narrow";
2040 break;
2041
2042 case '*':
265a9e55 2043 if (!NILP (current_buffer->read_only))
a2889657
JB
2044 return "%";
2045 if (MODIFF > current_buffer->save_modified)
2046 return "*";
2047 return "-";
2048
2049 case 's':
2050 /* status of process */
a2889657 2051 obj = Fget_buffer_process (Fcurrent_buffer ());
265a9e55 2052 if (NILP (obj))
a2889657
JB
2053 return "no process";
2054 obj = Fsymbol_name (Fprocess_status (obj));
2055 break;
a2889657
JB
2056
2057 case 'p':
2058 {
2059 int pos = marker_position (w->start);
2060 int total = ZV - BEGV;
2061
2062 if (XFASTINT (w->window_end_pos) <= Z - ZV)
2063 {
2064 if (pos <= BEGV)
2065 return "All";
2066 else
2067 return "Bottom";
2068 }
2069 else if (pos <= BEGV)
2070 return "Top";
2071 else
2072 {
2073 total = ((pos - BEGV) * 100 + total - 1) / total;
2074 /* We can't normally display a 3-digit number,
2075 so get us a 2-digit number that is close. */
2076 if (total == 100)
2077 total = 99;
2078 sprintf (decode_mode_spec_buf, "%2d%%", total);
2079 return decode_mode_spec_buf;
2080 }
2081 }
2082
2083 case '%':
2084 return "%";
2085
2086 case '[':
2087 {
2088 int i;
2089 char *p;
2090
2091 if (command_loop_level > 5)
2092 return "[[[... ";
2093 p = decode_mode_spec_buf;
2094 for (i = 0; i < command_loop_level; i++)
2095 *p++ = '[';
2096 *p = 0;
2097 return decode_mode_spec_buf;
2098 }
2099
2100 case ']':
2101 {
2102 int i;
2103 char *p;
2104
2105 if (command_loop_level > 5)
2106 return " ...]]]";
2107 p = decode_mode_spec_buf;
2108 for (i = 0; i < command_loop_level; i++)
2109 *p++ = ']';
2110 *p = 0;
2111 return decode_mode_spec_buf;
2112 }
2113
2114 case '-':
2115 {
2116 static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
2117 register char *p;
2118 register int i;
2119
2120 if (maxwidth < sizeof (lots_of_dashes))
2121 return lots_of_dashes;
2122 else
2123 {
2124 for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
2125 *p++ = '-';
2126 *p = '\0';
2127 }
2128 return decode_mode_spec_buf;
2129 }
2130 }
2131
2132 if (XTYPE (obj) == Lisp_String)
2133 return (char *) XSTRING (obj)->data;
2134 else
2135 return "";
2136}
2137\f
2138/* Display STRING on one line of window W, starting at HPOS.
2139 Display at position VPOS. Caller should have done get_display_line.
2140
2141 TRUNCATE is GLYPH to display at end if truncated. Zero for none.
2142
2143 MINCOL is the first column ok to end at. (Pad with spaces to this col.)
2144 MAXCOL is the last column ok to end at. Truncate here.
2145 -1 for MINCOL or MAXCOL means no explicit minimum or maximum.
2146 Both count from the left edge of the screen, as does HPOS.
2147 The right edge of W is an implicit maximum.
2148 If TRUNCATE is nonzero, the implicit maximum is one column before the edge.
2149
2150 Returns ending hpos */
2151
2152static int
2153display_string (w, vpos, string, hpos, truncate, mincol, maxcol)
2154 struct window *w;
2155 unsigned char *string;
2156 int vpos, hpos;
2157 GLYPH truncate;
2158 int mincol, maxcol;
2159{
2160 register int c;
2161 register GLYPH *p1;
2162 int hscroll = XINT (w->hscroll);
2163 int tab_width = XINT (current_buffer->tab_width);
2164 register GLYPH *start;
2165 register GLYPH *end;
2166 struct screen_glyphs *desired_glyphs = SCREEN_DESIRED_GLYPHS (XSCREEN (w->screen));
2167 GLYPH *p1start = desired_glyphs->glyphs[vpos] + hpos;
2168 int window_width = XFASTINT (w->width);
2169
2170 /* Use the standard display table, not the window's display table.
2171 We don't want the mode line in rot13. */
2172 register struct Lisp_Vector *dp = 0;
2173
2174 if (XTYPE (Vstandard_display_table) == Lisp_Vector
2175 && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
2176 dp = XVECTOR (Vstandard_display_table);
2177
2178 if (tab_width <= 0 || tab_width > 20) tab_width = 8;
2179
2180 p1 = p1start;
2181 start = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
2182 end = start + window_width - (truncate != 0);
2183
2184 if ((window_width + XFASTINT (w->left))
2185 != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w))))
2186 *end-- = '|';
2187
2188 if (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol)
2189 end = desired_glyphs->glyphs[vpos] + maxcol;
2190 if (maxcol >= 0 && mincol > maxcol)
2191 mincol = maxcol;
2192
2193 while (p1 < end)
2194 {
2195 c = *string++;
2196 if (!c) break;
2197 if (c >= 040 && c < 0177
2198 && (dp == 0 || XTYPE (DISP_CHAR_ROPE (dp, c)) != Lisp_String))
2199 {
2200 if (p1 >= start)
2201 *p1 = c;
2202 p1++;
2203 }
2204 else if (c == '\t')
2205 {
2206 do
2207 {
2208 if (p1 >= start && p1 < end)
2209 *p1 = SPACEGLYPH;
2210 p1++;
2211 }
2212 while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
2213 }
2214 else if (dp != 0 && XTYPE (DISP_CHAR_ROPE (dp, c)) == Lisp_String)
2215 p1 = copy_rope (p1, start, DISP_CHAR_ROPE (dp, c));
2216 else if (c < 0200 && buffer_defaults.ctl_arrow)
2217 {
2218 if (p1 >= start)
2219 *p1 = (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
2220 ? XINT (DISP_CTRL_GLYPH (dp)) : '^');
2221 p1++;
6e8290aa 2222 if (p1 >= start && p1 < end)
a2889657
JB
2223 *p1 = c ^ 0100;
2224 p1++;
2225 }
2226 else
2227 {
2228 if (p1 >= start)
2229 *p1 = (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
2230 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\');
2231 p1++;
6e8290aa 2232 if (p1 >= start && p1 < end)
a2889657
JB
2233 *p1 = (c >> 6) + '0';
2234 p1++;
6e8290aa 2235 if (p1 >= start && p1 < end)
a2889657
JB
2236 *p1 = (7 & (c >> 3)) + '0';
2237 p1++;
6e8290aa 2238 if (p1 >= start && p1 < end)
a2889657
JB
2239 *p1 = (7 & c) + '0';
2240 p1++;
2241 }
2242 }
2243
2244 if (c)
2245 {
2246 p1 = end;
2247 if (truncate) *p1++ = truncate;
2248 }
2249 else if (mincol >= 0)
2250 {
2251 end = desired_glyphs->glyphs[vpos] + mincol;
2252 while (p1 < end)
2253 *p1++ = SPACEGLYPH;
2254 }
2255
2256 {
2257 register int len = p1 - desired_glyphs->glyphs[vpos];
2258
2259 if (len > desired_glyphs->used[vpos])
2260 desired_glyphs->used[vpos] = len;
2261 desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
2262
2263 return len;
2264 }
2265}
2266\f
2267void
2268syms_of_xdisp ()
2269{
2270 staticpro (&last_arrow_position);
2271 staticpro (&last_arrow_string);
2272 last_arrow_position = Qnil;
2273 last_arrow_string = Qnil;
2274
2275 DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
2276 "String displayed by mode-line-format's \"%m\" specifiation.");
2277 Vglobal_mode_string = Qnil;
2278
2279 DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
2280 "Marker for where to display an arrow on top of the buffer text.\n\
2281This must be the beginning of a line in order to work.\n\
2282See also `overlay-arrow-string'.");
2283 Voverlay_arrow_position = Qnil;
2284
2285 DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
2286 "String to display as an arrow. See also `overlay-arrow-position'.");
2287 Voverlay_arrow_string = Qnil;
2288
2289 DEFVAR_INT ("scroll-step", &scroll_step,
2290 "*The number of lines to try scrolling a window by when point moves out.\n\
2291If that fails to bring point back on screen, point is centered instead.\n\
2292If this is zero, point is always centered after it moves off screen.");
2293
2294 DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
2295
2296 DEFVAR_BOOL ("truncate-partial-width-windows",
2297 &truncate_partial_width_windows,
2298 "*Non-nil means truncate lines in all windows less than full screen wide.");
2299 truncate_partial_width_windows = 1;
2300
2301 DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
2302 "*Non-nil means use inverse video for the mode line.");
2303 mode_line_inverse_video = 1;
a2889657
JB
2304}
2305
2306/* initialize the window system */
2307init_xdisp ()
2308{
2309 Lisp_Object root_window;
2310#ifndef COMPILER_REGISTER_BUG
2311 register
2312#endif /* COMPILER_REGISTER_BUG */
2313 struct window *mini_w;
2314
2315 this_line_bufpos = 0;
2316
2317 mini_w = XWINDOW (minibuf_window);
2318 root_window = mini_w->prev;
2319
2320 echo_area_glyphs = 0;
2321 previous_echo_glyphs = 0;
2322
2323 if (!noninteractive)
2324 {
2325 SCREEN_PTR s = XSCREEN (WINDOW_SCREEN (XWINDOW (root_window)));
2326 XFASTINT (XWINDOW (root_window)->top) = 0;
2327 set_window_height (root_window, SCREEN_HEIGHT (s) - 1, 0);
2328 XFASTINT (mini_w->top) = SCREEN_HEIGHT (s) - 1;
2329 set_window_height (minibuf_window, 1, 0);
2330
2331 XFASTINT (XWINDOW (root_window)->width) = SCREEN_WIDTH (s);
2332 XFASTINT (mini_w->width) = SCREEN_WIDTH (s);
2333 }
2334}