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