aboutsummaryrefslogtreecommitdiffstats
path: root/src/xdisp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xdisp.c')
-rw-r--r--src/xdisp.c2282
1 files changed, 2282 insertions, 0 deletions
diff --git a/src/xdisp.c b/src/xdisp.c
new file mode 100644
index 0000000000..cc5c3e3b8d
--- /dev/null
+++ b/src/xdisp.c
@@ -0,0 +1,2282 @@
+/* Display generation from window structure and buffer text.
+ Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "config.h"
+#include <stdio.h>
+/*#include <ctype.h>*/
+#undef NULL
+#include "lisp.h"
+#include "screen.h"
+#include "window.h"
+#include "termchar.h"
+#include "dispextern.h"
+#include "buffer.h"
+#include "indent.h"
+#include "commands.h"
+#include "macros.h"
+#include "disptab.h"
+
+extern int interrupt_input;
+extern int command_loop_level;
+
+/* Nonzero means print newline before next minibuffer message. */
+
+int noninteractive_need_newline;
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+/* The buffer position of the first character appearing
+ entirely or partially on the current screen line.
+ Or zero, which disables the optimization for the current screen line. */
+static int this_line_bufpos;
+
+/* Number of characters past the end of this line,
+ including the terminating newline */
+static int this_line_endpos;
+
+/* The vertical position of this screen line. */
+static int this_line_vpos;
+
+/* Hpos value for start of display on this screen line.
+ Usually zero, but negative if first character really began
+ on previous line */
+static int this_line_start_hpos;
+
+/* Buffer that this_line variables are describing. */
+static struct buffer *this_line_buffer;
+
+/* Set by try_window_id to the vpos of first of any lines
+ scrolled on to the bottom of the screen. These lines should
+ not be included in any general scroll computation. */
+static int scroll_bottom_vpos;
+
+/* Value of echo_area_glyphs when it was last acted on.
+ If this is nonzero, there is a message on the screen
+ in the minibuffer and it should be erased as soon
+ as it is no longer requested to appear. */
+char *previous_echo_glyphs;
+
+/* Nonzero means truncate lines in all windows less wide than the screen */
+int truncate_partial_width_windows;
+
+Lisp_Object Vglobal_mode_string;
+
+/* Marker for where to display an arrow on top of the buffer text. */
+Lisp_Object Voverlay_arrow_position;
+
+/* String to display for the arrow. */
+Lisp_Object Voverlay_arrow_string;
+
+/* Values of those variables at last redisplay. */
+Lisp_Object last_arrow_position, last_arrow_string;
+
+/* Nonzero if overlay arrow has been displayed once in this window. */
+static int overlay_arrow_seen;
+
+/* If cursor motion alone moves point off screen,
+ Try scrolling this many lines up or down if that will bring it back. */
+int scroll_step;
+
+/* Nonzero if try_window_id has made blank lines at window bottom
+ since the last redisplay that paused */
+static int blank_end_of_window;
+
+/* Number of windows showing the buffer of the selected window.
+ keyboard.c refers to this. */
+int buffer_shared;
+
+/* display_text_line sets these to the screen position (origin 0) of point,
+ whether the window is selected or not.
+ Set one to -1 first to determine whether point was found afterwards. */
+
+static int cursor_vpos;
+static int cursor_hpos;
+
+int debug_end_pos;
+
+/* Nonzero means display mode line highlighted */
+int mode_line_inverse_video;
+
+static void echo_area_display ();
+void mark_window_display_accurate ();
+static void redisplay_windows ();
+static void redisplay_window ();
+static void try_window ();
+static int try_window_id ();
+static struct position *display_text_line ();
+static void display_mode_line ();
+static int display_mode_element ();
+static char *fmodetrunc ();
+static char *decode_mode_spec ();
+static int display_string ();
+
+/* Prompt to display in front of the minibuffer contents */
+char *minibuf_prompt;
+
+/* Width in columns of current minibuffer prompt. */
+int minibuf_prompt_width;
+
+/* Message to display instead of minibuffer contents
+ This is what the functions error and message make,
+ and command echoing uses it as well.
+ It overrides the minibuf_prompt as well as the buffer. */
+char *echo_area_glyphs;
+
+/* true iff we should redraw the mode lines on the next redisplay */
+int update_mode_lines;
+
+/* Smallest number of characters before the gap
+ at any time since last redisplay that finished.
+ Valid for current buffer when try_window_id can be called. */
+int beg_unchanged;
+
+/* Smallest number of characters after the gap
+ at any time since last redisplay that finished.
+ Valid for current buffer when try_window_id can be called. */
+int end_unchanged;
+
+/* MODIFF as of last redisplay that finished;
+ if it matches MODIFF, beg_unchanged and end_unchanged
+ contain no useful information */
+int unchanged_modified;
+
+/* Nonzero if head_clip or tail_clip of current buffer has changed
+ since last redisplay that finished */
+int clip_changed;
+
+/* Nonzero if window sizes or contents have changed
+ since last redisplay that finished */
+int windows_or_buffers_changed;
+
+
+#ifndef MULTI_SCREEN
+
+DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "",
+ "Clear the screen and output again what is supposed to appear on it.")
+ ()
+{
+ if (screen_height == 0) abort (); /* Some bug zeros some core */
+ clear_screen ();
+ fflush (stdout);
+ clear_screen_records ();
+ if (screen_height == 0) abort (); /* Some bug zeros some core */
+ windows_or_buffers_changed++;
+ /* Mark all windows as INaccurate,
+ so that every window will have its redisplay done. */
+ mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 0);
+ if (screen_height == 0) abort (); /* Some bug zeros some core */
+ return Qnil;
+}
+
+#endif /* not MULTI_SCREEN */
+
+char *message_buf;
+
+/* dump an informative message to the minibuf */
+/* VARARGS 1 */
+
+void
+message (m, a1, a2, a3)
+ char *m;
+{
+ if (noninteractive)
+ {
+ if (noninteractive_need_newline)
+ putc ('\n', stderr);
+ noninteractive_need_newline = 0;
+ fprintf (stderr, m, a1, a2, a3);
+ fprintf (stderr, "\n");
+ fflush (stderr);
+ }
+ else if (INTERACTIVE)
+ {
+#ifdef NO_ARG_ARRAY
+ int a[3];
+ a[0] = a1;
+ a[1] = a2;
+ a[2] = a3;
+
+ doprnt (SCREEN_MESSAGE_BUF (selected_screen),
+ SCREEN_WIDTH (selected_screen), m, 0, 3, a);
+#else
+ doprnt (SCREEN_MESSAGE_BUF (selected_screen),
+ SCREEN_WIDTH (selected_screen), m, 0, 3, &a1);
+#endif /* NO_ARG_ARRAY */
+
+ echo_area_glyphs = SCREEN_MESSAGE_BUF (selected_screen);
+ do_pending_window_change ();
+ echo_area_display ();
+ update_screen (XSCREEN (XWINDOW (minibuf_window)->screen), 1, 1);
+ do_pending_window_change ();
+ }
+}
+
+/* Specify m, a string, as a message in the minibuf. */
+void
+message1 (m)
+ char *m;
+{
+ if (!NULL (Vwindow_system) && SCREEN_IS_TERMCAP (selected_screen))
+ return;
+
+ if (noninteractive)
+ {
+ if (noninteractive_need_newline)
+ putc ('\n', stderr);
+ noninteractive_need_newline = 0;
+ fprintf (stderr, "%s\n", m);
+ fflush (stderr);
+ }
+ else if (INTERACTIVE)
+ {
+ echo_area_glyphs = m;
+ do_pending_window_change ();
+ echo_area_display ();
+ update_screen (XSCREEN (XWINDOW (minibuf_window)->screen), 1, 1);
+ do_pending_window_change ();
+ }
+}
+
+static void
+echo_area_display ()
+{
+ register int vpos;
+ SCREEN_PTR s;
+
+#ifdef MULTI_SCREEN
+ choose_minibuf_screen ();
+ s = XSCREEN (XWINDOW (minibuf_window)->screen);
+
+ if (!s->visible)
+ return;
+#endif
+
+ if (screen_garbaged)
+ {
+ Fredraw_display ();
+ screen_garbaged = 0;
+ }
+
+ if (echo_area_glyphs || minibuf_level == 0)
+ {
+ vpos = XFASTINT (XWINDOW (minibuf_window)->top);
+ get_display_line (s, vpos, 0);
+ display_string (XWINDOW (minibuf_window), vpos,
+ echo_area_glyphs ? echo_area_glyphs : "",
+ 0, 0, 0, SCREEN_WIDTH (s));
+
+ /* If desired cursor location is on this line, put it at end of text */
+ if (SCREEN_CURSOR_Y (s) == vpos)
+ SCREEN_CURSOR_X (s) = s->desired_glyphs->used[vpos];
+ }
+ else if (!EQ (minibuf_window, selected_window))
+ windows_or_buffers_changed++;
+
+ if (EQ (minibuf_window, selected_window))
+ this_line_bufpos = 0;
+
+ previous_echo_glyphs = echo_area_glyphs;
+}
+
+/* Do a screen update, taking possible shortcuts into account.
+ This is the main external entry point for redisplay.
+
+ If the last redisplay displayed an echo area message and that
+ message is no longer requested, we clear the echo area
+ or bring back the minibuffer if that is in use.
+
+ Everyone would like to have a hook here to call eval,
+ but that cannot be done safely without a lot of changes elsewhere.
+ This can be called from signal handlers; with alarms set up;
+ or with synchronous processes running.
+ See the function `echo' in keyboard.c.
+ See Fcall_process; if you called it from here, it could be
+ entered recursively. */
+
+void
+redisplay ()
+{
+ register struct window *w = XWINDOW (selected_window);
+ register int pause;
+ int must_finish = 0;
+ int all_windows;
+ register int tlbufpos, tlendpos;
+ struct position pos;
+ extern int input_pending;
+
+ if (noninteractive)
+ return;
+
+ /* Notice any pending interrupt request to change screen size. */
+ do_pending_window_change ();
+
+ if (screen_garbaged)
+ {
+ Fredraw_display ();
+ screen_garbaged = 0;
+ }
+
+ if (echo_area_glyphs || previous_echo_glyphs)
+ {
+ echo_area_display ();
+ must_finish = 1;
+ }
+
+ if (clip_changed || windows_or_buffers_changed)
+ update_mode_lines++;
+
+ /* Detect case that we need to write a star in the mode line. */
+ if (XFASTINT (w->last_modified) < MODIFF
+ && XFASTINT (w->last_modified) <= current_buffer->save_modified)
+ {
+ w->update_mode_line = Qt;
+ if (buffer_shared > 1)
+ update_mode_lines++;
+ }
+
+ SCREEN_SCROLL_BOTTOM_VPOS (XSCREEN (w->screen)) = -1;
+
+ all_windows = update_mode_lines || buffer_shared > 1;
+#ifdef MULTI_SCREEN
+ all_windows |= (XTYPE (Vglobal_minibuffer_screen) == Lisp_Screen
+ && selected_screen != XSCREEN (Vglobal_minibuffer_screen));
+#endif /* MULTI_SCREEN */
+
+ /* If specs for an arrow have changed, do thorough redisplay
+ to ensure we remove any arrow that should no longer exist. */
+ if (Voverlay_arrow_position != last_arrow_position
+ || Voverlay_arrow_string != last_arrow_string)
+ all_windows = 1, clip_changed = 1;
+
+ tlbufpos = this_line_bufpos;
+ tlendpos = this_line_endpos;
+ if (!all_windows && tlbufpos > 0 && NULL (w->update_mode_line)
+ && SCREEN_VISIBLE_P (XSCREEN (w->screen))
+ /* Make sure recorded data applies to current buffer, etc */
+ && this_line_buffer == current_buffer
+ && current_buffer == XBUFFER (w->buffer)
+ && NULL (w->force_start)
+ /* Point must be on the line that we have info recorded about */
+ && point >= tlbufpos
+ && point <= Z - tlendpos
+ /* All text outside that line, including its final newline,
+ must be unchanged */
+ && (XFASTINT (w->last_modified) >= MODIFF
+ || (beg_unchanged >= tlbufpos - 1
+ && GPT >= tlbufpos
+ && end_unchanged >= tlendpos
+ && Z - GPT >= tlendpos)))
+ {
+ if (tlbufpos > BEGV && FETCH_CHAR (tlbufpos - 1) != '\n'
+ && (tlbufpos == ZV
+ || FETCH_CHAR (tlbufpos) == '\n'))
+ /* Former continuation line has disappeared by becoming empty */
+ goto cancel;
+ else if (XFASTINT (w->last_modified) < MODIFF
+ || MINI_WINDOW_P (w))
+ {
+ cursor_vpos = -1;
+ overlay_arrow_seen = 0;
+ display_text_line (w, tlbufpos, this_line_vpos, this_line_start_hpos,
+ pos_tab_offset (w, tlbufpos));
+ /* If line contains point, is not continued,
+ and ends at same distance from eob as before, we win */
+ if (cursor_vpos >= 0 && this_line_bufpos
+ && this_line_endpos == tlendpos)
+ {
+ if (XFASTINT (w->width) != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w))))
+ preserve_other_columns (w);
+ goto update;
+ }
+ else
+ goto cancel;
+ }
+ else if (point == XFASTINT (w->last_point))
+ {
+ if (!must_finish)
+ {
+ do_pending_window_change ();
+ return;
+ }
+ goto update;
+ }
+ else
+ {
+ pos = *compute_motion (tlbufpos, 0,
+ XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
+ point, 2, - (1 << (SHORTBITS - 1)),
+ XFASTINT (w->width) - 1
+ - (XFASTINT (w->width) + XFASTINT (w->left)
+ != SCREEN_WIDTH (selected_screen)),
+ XINT (w->hscroll), 0);
+ if (pos.vpos < 1)
+ {
+ SCREEN_CURSOR_X (selected_screen)
+ = XFASTINT (w->left) + max (pos.hpos, 0);
+ SCREEN_CURSOR_Y (selected_screen) = this_line_vpos;
+ goto update;
+ }
+ else
+ goto cancel;
+ }
+ cancel:
+ /* Text changed drastically or point moved off of line */
+ cancel_line (this_line_vpos, selected_screen);
+ }
+
+ this_line_bufpos = 0;
+ all_windows |= buffer_shared > 1;
+
+ if (all_windows)
+ {
+#ifdef MULTI_SCREEN
+ Lisp_Object tail;
+
+ /* Recompute # windows showing selected buffer.
+ This will be increment each time such a window is displayed. */
+ buffer_shared = 0;
+
+ for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr)
+ {
+ SCREEN_PTR s;
+
+ if (XTYPE (XCONS (tail)->car) != Lisp_Screen)
+ continue;
+
+ s = XSCREEN (XCONS (tail)->car);
+ if (s->visible)
+ {
+
+ /* Clear the echo area on screens where the minibuffer isn't. */
+ if (s != XSCREEN (XWINDOW (minibuf_window)->screen)
+ /* But only screens that have minibuffers. */
+ && s->has_minibuffer)
+ {
+ int vpos = XFASTINT (XWINDOW (s->minibuffer_window)->top);
+ register struct screen_glyphs *line;
+
+ get_display_line (s, vpos, 0);
+ display_string (XWINDOW (s->minibuffer_window), vpos, "",
+ 0, 0, 0, s->width);
+ }
+
+ /* Redraw its windows. */
+ redisplay_windows (SCREEN_ROOT_WINDOW (s));
+ }
+ }
+#else
+ redisplay_windows (SCREEN_ROOT_WINDOW (s));
+#endif /* not MULTI_SCREEN */
+ }
+ else if (SCREEN_VISIBLE_P (selected_screen))
+ {
+ redisplay_window (selected_window, 1);
+ if (XFASTINT (w->width) != SCREEN_WIDTH (selected_screen))
+ preserve_other_columns (w);
+ }
+
+update:
+ /* Prevent various kinds of signals during display update.
+ stdio is not robust about handling signals,
+ which can cause an apparent I/O error. */
+ if (interrupt_input)
+ unrequest_sigio ();
+ stop_polling ();
+
+#ifdef MULTI_SCREEN
+ if (all_windows)
+ {
+ Lisp_Object tail;
+
+ pause = 0;
+
+ for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr)
+ {
+ SCREEN_PTR s;
+
+ if (XTYPE (XCONS (tail)->car) != Lisp_Screen)
+ continue;
+
+ s = XSCREEN (XCONS (tail)->car);
+ if (s->visible)
+ {
+ pause |= update_screen (s, 0, 0, SCREEN_SCROLL_BOTTOM_VPOS (s));
+ if (!pause)
+ mark_window_display_accurate (s->root_window, 1);
+ }
+ }
+ }
+ else
+#endif /* MULTI_SCREEN */
+ if (SCREEN_VISIBLE_P (selected_screen))
+ pause = update_screen (selected_screen, 0, 0);
+
+ /* If screen does not match, prevent doing single-line-update next time.
+ Also, don't forget to check every line to update the arrow. */
+ if (pause)
+ {
+ this_line_bufpos = 0;
+ if (!NULL (last_arrow_position))
+ {
+ last_arrow_position = Qt;
+ last_arrow_string = Qt;
+ }
+ /* If we pause after scrolling, some lines in current_screen
+ may be null, so preserve_other_columns won't be able to
+ preserve all the vertical-bar separators. So, avoid using it
+ in that case. */
+ if (XFASTINT (w->width) != SCREEN_WIDTH (selected_screen))
+ update_mode_lines = 1;
+ }
+
+ /* Now text on screen agrees with windows, so
+ put info into the windows for partial redisplay to follow */
+
+ if (!pause)
+ {
+ register struct buffer *b = XBUFFER (w->buffer);
+
+ blank_end_of_window = 0;
+ clip_changed = 0;
+ unchanged_modified = BUF_MODIFF (b);
+ beg_unchanged = BUF_GPT (b) - BUF_BEG (b);
+ end_unchanged = BUF_Z (b) - BUF_GPT (b);
+
+ XFASTINT (w->last_point) = BUF_PT (b);
+ XFASTINT (w->last_point_x) = SCREEN_CURSOR_X (selected_screen);
+ XFASTINT (w->last_point_y) = SCREEN_CURSOR_Y (selected_screen);
+
+ if (all_windows)
+ mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 1);
+ else
+ {
+ w->update_mode_line = Qnil;
+ XFASTINT (w->last_modified) = BUF_MODIFF (b);
+ w->window_end_valid = Qt;
+ last_arrow_position = Voverlay_arrow_position;
+ last_arrow_string = Voverlay_arrow_string;
+ }
+ update_mode_lines = 0;
+ windows_or_buffers_changed = 0;
+ }
+
+ /* Start SIGIO interrupts coming again.
+ Having them off during the code above
+ makes it less likely one will discard output,
+ but not impossible, since there might be stuff
+ in the system buffer here.
+ But it is much hairier to try to do anything about that. */
+
+ if (interrupt_input)
+ request_sigio ();
+ start_polling ();
+
+ /* Change screen size now if a change is pending. */
+ do_pending_window_change ();
+}
+
+/* Redisplay, but leave alone any recent echo area message
+ unless another message has been requested in its place.
+
+ This is useful in situations where you need to redisplay but no
+ user action has occurred, making it inappropriate for the message
+ area to be cleared. See tracking_off and
+ wait_reading_process_input for examples of these situations. */
+
+redisplay_preserve_echo_area ()
+{
+ if (echo_area_glyphs == 0 && previous_echo_glyphs != 0)
+ {
+ echo_area_glyphs = previous_echo_glyphs;
+ redisplay ();
+ echo_area_glyphs = 0;
+ }
+ else
+ redisplay ();
+}
+
+void
+mark_window_display_accurate (window, flag)
+ Lisp_Object window;
+ int flag;
+{
+ register struct window *w;
+
+ for (;!NULL (window); window = w->next)
+ {
+ w = XWINDOW (window);
+
+ if (!NULL (w->buffer))
+ XFASTINT (w->last_modified)
+ = !flag ? 0
+ : XBUFFER (w->buffer) == current_buffer
+ ? MODIFF : BUF_MODIFF (XBUFFER (w->buffer));
+ w->window_end_valid = Qt;
+ w->update_mode_line = Qnil;
+
+ if (!NULL (w->vchild))
+ mark_window_display_accurate (w->vchild, flag);
+ if (!NULL (w->hchild))
+ mark_window_display_accurate (w->hchild, flag);
+ }
+
+ if (flag)
+ {
+ last_arrow_position = Voverlay_arrow_position;
+ last_arrow_string = Voverlay_arrow_string;
+ }
+ else
+ {
+ /* t is unequal to any useful value of Voverlay_arrow_... */
+ last_arrow_position = Qt;
+ last_arrow_string = Qt;
+ }
+}
+
+int do_id = 1;
+
+static void
+redisplay_windows (window)
+ Lisp_Object window;
+{
+ for (; !NULL (window); window = XWINDOW (window)->next)
+ redisplay_window (window, 0);
+}
+
+static void
+redisplay_window (window, just_this_one)
+ Lisp_Object window;
+ int just_this_one;
+{
+ register struct window *w = XWINDOW (window);
+ SCREEN_PTR s = XSCREEN (w->screen);
+ int height;
+ register int lpoint = point;
+ struct buffer *old = current_buffer;
+ register int width = XFASTINT (w->width) - 1
+ - (XFASTINT (w->width) + XFASTINT (w->left)
+ != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w))));
+ register int startp;
+ register int hscroll = XINT (w->hscroll);
+ struct position pos;
+ int opoint;
+ int tem;
+ int window_needs_modeline;
+
+ if (SCREEN_HEIGHT (s) == 0) abort (); /* Some bug zeros some core */
+
+ /* If this is a combination window, do its children; that's all. */
+
+ if (!NULL (w->vchild))
+ {
+ redisplay_windows (w->vchild);
+ return;
+ }
+ if (!NULL (w->hchild))
+ {
+ redisplay_windows (w->hchild);
+ return;
+ }
+ if (NULL (w->buffer))
+ abort ();
+
+ if (update_mode_lines)
+ w->update_mode_line = Qt;
+
+ /* Otherwise set up data on this window; select its buffer and point value */
+
+ height = window_internal_height (w);
+
+ if (MINI_WINDOW_P (w)
+ && (echo_area_glyphs
+ /* Don't display minibuffers except minibuf_window. */
+ || w != XWINDOW (minibuf_window)))
+ return;
+
+ current_buffer = XBUFFER (w->buffer);
+ opoint = point;
+
+ /* Count number of windows showing the selected buffer. */
+
+ if (!just_this_one
+ && current_buffer == XBUFFER (XWINDOW (selected_window)->buffer))
+ buffer_shared++;
+
+ /* POINT refers normally to the selected window.
+ For any other window, set up appropriate value. */
+
+ if (!EQ (window, selected_window))
+ {
+ SET_PT (marker_position (w->pointm));
+ if (point < BEGV)
+ {
+ point = BEGV;
+ Fset_marker (w->pointm, make_number (point), Qnil);
+ }
+ else if (point > (ZV - 1))
+ {
+ point = ZV;
+ Fset_marker (w->pointm, make_number (point), Qnil);
+ }
+ }
+
+ /* If window-start is screwed up, choose a new one. */
+
+ if (XMARKER (w->start)->buffer != current_buffer)
+ goto recenter;
+
+ startp = marker_position (w->start);
+
+ /* Handle case where place to start displaying has been specified */
+
+ if (!NULL (w->force_start))
+ {
+ w->update_mode_line = Qt;
+ w->force_start = Qnil;
+ XFASTINT (w->last_modified) = 0;
+ try_window (window, startp);
+ if (cursor_vpos < 0)
+ {
+ /* If point does not appear, move point so it does appear */
+ pos = *compute_motion (startp, 0,
+ ((EQ (window, minibuf_window) && startp == 1)
+ ? minibuf_prompt_width : 0)
+ +
+ (hscroll ? 1 - hscroll : 0),
+ ZV, height / 2,
+ - (1 << (SHORTBITS - 1)),
+ width, hscroll, pos_tab_offset (w, startp));
+ SET_PT (pos.bufpos);
+ if (w != XWINDOW (SCREEN_SELECTED_WINDOW (s)))
+ Fset_marker (w->pointm, make_number (point), Qnil);
+ else
+ {
+ lpoint = point;
+ SCREEN_CURSOR_X (s) = max (0, pos.hpos) + XFASTINT (w->left);
+ SCREEN_CURSOR_Y (s) = pos.vpos + XFASTINT (w->top);
+ }
+ }
+ goto done;
+ }
+
+ /* Handle case where text has not changed, only point,
+ and it has not moved off the screen */
+
+ /* This code is not used for minibuffer for the sake of
+ the case of redisplaying to replace an echo area message;
+ since in that case the minibuffer contents per se are usually unchanged.
+ This code is of no real use in the minibuffer since
+ the handling of this_line_bufpos, etc.,
+ in redisplay handles the same cases. */
+
+ if (XFASTINT (w->last_modified) >= MODIFF
+ && point >= startp && !clip_changed
+ && (just_this_one || XFASTINT (w->width) == SCREEN_WIDTH (s))
+ && !EQ (window, minibuf_window))
+ {
+ pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
+ point, height + 1, 10000, width, hscroll,
+ pos_tab_offset (w, startp));
+
+ if (pos.vpos < height)
+ {
+ /* Ok, point is still on screen */
+ if (w == XWINDOW (SCREEN_SELECTED_WINDOW (s)))
+ {
+ /* These variables are supposed to be origin 1 */
+ SCREEN_CURSOR_X (s) = max (0, pos.hpos) + XFASTINT (w->left);
+ SCREEN_CURSOR_Y (s) = pos.vpos + XFASTINT (w->top);
+ }
+ /* This doesn't do the trick, because if a window to the right of
+ this one must be redisplayed, this does nothing because there
+ is nothing in DesiredScreen yet, and then the other window is
+ redisplayed, making likes that are empty in this window's columns.
+ if (XFASTINT (w->width) != SCREEN_WIDTH (s))
+ preserve_my_columns (w);
+ */
+ goto done;
+ }
+ /* Don't bother trying redisplay with same start;
+ we already know it will lose */
+ }
+ /* If current starting point was originally the beginning of a line
+ but no longer is, find a new starting point. */
+ else if (!NULL (w->start_at_line_beg)
+ && !(startp == BEGV
+ || FETCH_CHAR (startp - 1) == '\n'))
+ {
+ goto recenter;
+ }
+ else if (just_this_one && !MINI_WINDOW_P (w)
+ && point >= startp
+ && XFASTINT (w->last_modified)
+ && ! EQ (w->window_end_valid, Qnil)
+ && do_id && !clip_changed
+ && !blank_end_of_window
+ && XFASTINT (w->width) == SCREEN_WIDTH (s)
+ && EQ (last_arrow_position, Voverlay_arrow_position)
+ && EQ (last_arrow_string, Voverlay_arrow_string)
+ && (tem = try_window_id (SCREEN_SELECTED_WINDOW (s)))
+ && tem != -2)
+ {
+ /* tem > 0 means success. tem == -1 means choose new start.
+ tem == -2 means try again with same start,
+ and nothing but whitespace follows the changed stuff.
+ tem == 0 means try again with same start. */
+ if (tem > 0)
+ goto done;
+ }
+ else if (startp >= BEGV && startp <= ZV
+ /* Avoid starting display at end of buffer! */
+ && (startp <= ZV || startp == BEGV
+ || (XFASTINT (w->last_modified) >= MODIFF)))
+ {
+ /* Try to redisplay starting at same place as before */
+ /* If point has not moved off screen, accept the results */
+ try_window (window, startp);
+ if (cursor_vpos >= 0)
+ goto done;
+ else
+ cancel_my_columns (w);
+ }
+
+ XFASTINT (w->last_modified) = 0;
+ w->update_mode_line = Qt;
+
+ /* Try to scroll by specified few lines */
+
+ if (scroll_step && !clip_changed)
+ {
+ if (point > startp)
+ {
+ pos = *vmotion (Z - XFASTINT (w->window_end_pos),
+ scroll_step, width, hscroll, window);
+ if (pos.vpos >= height)
+ goto scroll_fail;
+ }
+
+ pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step,
+ width, hscroll, window);
+
+ if (point >= pos.bufpos)
+ {
+ try_window (window, pos.bufpos);
+ if (cursor_vpos >= 0)
+ goto done;
+ else
+ cancel_my_columns (w);
+ }
+ scroll_fail: ;
+ }
+
+ /* Finally, just choose place to start which centers point */
+
+recenter:
+ pos = *vmotion (point, - height / 2, width, hscroll, window);
+ try_window (window, pos.bufpos);
+
+ startp = marker_position (w->start);
+ w->start_at_line_beg =
+ (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
+
+done:
+ /* If window not full width, must redo its mode line
+ if the window to its side is being redone */
+ if ((!NULL (w->update_mode_line)
+ || (!just_this_one && width < SCREEN_WIDTH (s) - 1))
+ && height != XFASTINT (w->height))
+ display_mode_line (w);
+
+ SET_PT (opoint);
+ current_buffer = old;
+ SET_PT (lpoint);
+}
+
+/* Do full redisplay on one window, starting at position `pos'. */
+
+static void
+try_window (window, pos)
+ Lisp_Object window;
+ register int pos;
+{
+ register struct window *w = XWINDOW (window);
+ register int height = window_internal_height (w);
+ register int vpos = XFASTINT (w->top);
+ register int last_text_vpos = vpos;
+ int tab_offset = pos_tab_offset (w, pos);
+ SCREEN_PTR s = XSCREEN (w->screen);
+ int width = XFASTINT (w->width) - 1
+ - (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s));
+ struct position val;
+
+ Fset_marker (w->start, make_number (pos), Qnil);
+ cursor_vpos = -1;
+ overlay_arrow_seen = 0;
+ val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
+
+ while (--height >= 0)
+ {
+ val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
+ tab_offset += width;
+ if (val.vpos) tab_offset = 0;
+ vpos++;
+ if (pos != val.bufpos)
+ last_text_vpos
+ /* Next line, unless prev line ended in end of buffer with no cr */
+ = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
+ pos = val.bufpos;
+ }
+
+ /* If last line is continued in middle of character,
+ include the split character in the text considered on the screen */
+ if (val.hpos < (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
+ pos++;
+
+ /* If bottom just moved off end of screen, change mode line percentage. */
+ if (XFASTINT (w->window_end_pos) == 0
+ && Z != pos)
+ w->update_mode_line = Qt;
+
+ /* Say where last char on screen will be, once redisplay is finished. */
+ XFASTINT (w->window_end_pos) = Z - pos;
+ XFASTINT (w->window_end_vpos) = last_text_vpos - XFASTINT (w->top);
+ /* But that is not valid info until redisplay finishes. */
+ w->window_end_valid = Qnil;
+}
+
+/* Try to redisplay when buffer is modified locally,
+ computing insert/delete line to preserve text outside
+ the bounds of the changes.
+ Return 1 if successful, 0 if if cannot tell what to do,
+ or -1 to tell caller to find a new window start,
+ or -2 to tell caller to do normal redisplay with same window start. */
+
+static int
+try_window_id (window)
+ Lisp_Object window;
+{
+ int pos;
+ register struct window *w = XWINDOW (window);
+ register int height = window_internal_height (w);
+ SCREEN_PTR s = XSCREEN (w->screen);
+ int top = XFASTINT (w->top);
+ int start = marker_position (w->start);
+ int width = XFASTINT (w->width) - 1
+ - (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s));
+ int hscroll = XINT (w->hscroll);
+ int lmargin = hscroll > 0 ? 1 - hscroll : 0;
+ register int vpos;
+ register int i, tem;
+ int last_text_vpos = 0;
+ int stop_vpos;
+
+ struct position val, bp, ep, xp, pp;
+ int scroll_amount = 0;
+ int delta;
+ int tab_offset, epto;
+
+ if (GPT - BEG < beg_unchanged)
+ beg_unchanged = GPT - BEG;
+ if (Z - GPT < end_unchanged)
+ end_unchanged = Z - GPT;
+
+ if (beg_unchanged + 1 < start)
+ return 0; /* Give up if changes go above top of window */
+
+ /* Find position before which nothing is changed. */
+ bp = *compute_motion (start, 0, lmargin,
+ beg_unchanged + 1, 10000, 10000, width, hscroll,
+ pos_tab_offset (w, start));
+ if (bp.vpos >= height)
+ return point < bp.bufpos && !bp.contin;
+
+ vpos = bp.vpos;
+
+ /* Find beginning of that screen line. Must display from there. */
+ bp = *vmotion (bp.bufpos, 0, width, hscroll, window);
+
+ pos = bp.bufpos;
+ val.hpos = lmargin;
+ if (pos < start)
+ return -1;
+
+ /* If about to start displaying at the beginning of a continuation line,
+ really start with previous screen line, in case it was not
+ continued when last redisplayed */
+ if (bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0)
+ {
+ bp = *vmotion (bp.bufpos, -1, width, hscroll, window);
+ --vpos;
+ pos = bp.bufpos;
+ }
+
+ if (bp.contin && bp.hpos != lmargin)
+ {
+ val.hpos = bp.prevhpos - width + lmargin;
+ pos--;
+ }
+
+ bp.vpos = vpos;
+
+ /* Find first visible newline after which no more is changed. */
+ tem = find_next_newline (Z - max (end_unchanged, Z - ZV), 1);
+ if (XTYPE (current_buffer->selective_display) == Lisp_Int
+ && XINT (current_buffer->selective_display) > 0)
+ while (tem < ZV - 1
+ && (position_indentation (tem)
+ >= XINT (current_buffer->selective_display)))
+ tem = find_next_newline (tem, 1);
+
+ /* Compute the cursor position after that newline. */
+ ep = *compute_motion (pos, vpos, val.hpos, tem,
+ height, - (1 << (SHORTBITS - 1)),
+ width, hscroll, pos_tab_offset (w, bp.bufpos));
+
+ /* If changes reach past the text available on the screen,
+ just display rest of screen. */
+ if (ep.bufpos > Z - XFASTINT (w->window_end_pos))
+ stop_vpos = height;
+ else
+ stop_vpos = ep.vpos;
+
+ /* If no newline before ep, the line ep is on includes some changes
+ that must be displayed. Make sure we don't stop before it. */
+ /* Also, if changes reach all the way until ep.bufpos,
+ it is possible that something was deleted after the
+ newline before it, so the following line must be redrawn. */
+ if (stop_vpos == ep.vpos
+ && (ep.bufpos == BEGV
+ || FETCH_CHAR (ep.bufpos - 1) != '\n'
+ || ep.bufpos == Z - end_unchanged))
+ stop_vpos = ep.vpos + 1;
+
+ cursor_vpos = -1;
+ overlay_arrow_seen = 0;
+
+ /* If changes do not reach to bottom of window,
+ figure out how much to scroll the rest of the window */
+ if (stop_vpos < height)
+ {
+ /* Now determine how far up or down the rest of the window has moved */
+ epto = pos_tab_offset (w, ep.bufpos);
+ xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
+ Z - XFASTINT (w->window_end_pos),
+ 10000, 0, width, hscroll, epto);
+ scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
+
+ /* Is everything on screen below the changes whitespace?
+ If so, no scrolling is really necessary. */
+ for (i = ep.bufpos; i < xp.bufpos; i++)
+ {
+ tem = FETCH_CHAR (i);
+ if (tem != ' ' && tem != '\n' && tem != '\t')
+ break;
+ }
+ if (i == xp.bufpos)
+ return -2;
+
+ XFASTINT (w->window_end_vpos) += scroll_amount;
+
+ /* Before doing any scrolling, verify that point will be on screen. */
+ if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height))
+ {
+ if (point <= xp.bufpos)
+ {
+ pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
+ point, height, - (1 << (SHORTBITS - 1)),
+ width, hscroll, epto);
+ }
+ else
+ {
+ pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
+ point, height, - (1 << (SHORTBITS - 1)),
+ width, hscroll, pos_tab_offset (w, xp.bufpos));
+ }
+ if (pp.bufpos < point || pp.vpos == height)
+ return 0;
+ cursor_vpos = pp.vpos + top;
+ cursor_hpos = pp.hpos + XFASTINT (w->left);
+ }
+
+ if (stop_vpos - scroll_amount >= height
+ || ep.bufpos == xp.bufpos)
+ {
+ if (scroll_amount < 0)
+ stop_vpos -= scroll_amount;
+ scroll_amount = 0;
+ /* In this path, we have altered window_end_vpos
+ and not left it negative.
+ We must make sure that, in case display is preempted
+ before the screen changes to reflect what we do here,
+ further updates will not come to try_window_id
+ and assume the screen and window_end_vpos match. */
+ blank_end_of_window = 1;
+ }
+ else if (!scroll_amount)
+ {}
+ else if (bp.bufpos == Z - end_unchanged)
+ {
+ /* If reprinting everything is nearly as fast as scrolling,
+ don't bother scrolling. Can happen if lines are short. */
+ if (scroll_cost (s, bp.vpos + top - scroll_amount,
+ top + height - max (0, scroll_amount),
+ scroll_amount)
+ > xp.bufpos - bp.bufpos - 20)
+ /* Return "try normal display with same window-start."
+ Too bad we can't prevent further scroll-thinking. */
+ return -2;
+ /* If pure deletion, scroll up as many lines as possible.
+ In common case of killing a line, this can save the
+ following line from being overwritten by scrolling
+ and therefore having to be redrawn. */
+ tem = scroll_screen_lines (s, bp.vpos + top - scroll_amount,
+ top + height - max (0, scroll_amount),
+ scroll_amount);
+ if (!tem) stop_vpos = height;
+ }
+ else if (scroll_amount)
+ {
+ /* If reprinting everything is nearly as fast as scrolling,
+ don't bother scrolling. Can happen if lines are short. */
+ /* Note that if scroll_amount > 0, xp.bufpos - bp.bufpos is an
+ overestimate of cost of reprinting, since xp.bufpos
+ would end up below the bottom of the window. */
+ if (scroll_cost (s, ep.vpos + top - scroll_amount,
+ top + height - max (0, scroll_amount),
+ scroll_amount)
+ > xp.bufpos - ep.bufpos - 20)
+ /* Return "try normal display with same window-start."
+ Too bad we can't prevent further scroll-thinking. */
+ return -2;
+ tem = scroll_screen_lines (s, ep.vpos + top - scroll_amount,
+ top + height - max (0, scroll_amount),
+ scroll_amount);
+ if (!tem) stop_vpos = height;
+ }
+ }
+
+ /* In any case, do not display past bottom of window */
+ if (stop_vpos >= height)
+ {
+ stop_vpos = height;
+ scroll_amount = 0;
+ }
+
+ /* Handle case where pos is before w->start --
+ can happen if part of line had been clipped and is not clipped now */
+ if (vpos == 0 && pos < marker_position (w->start))
+ Fset_marker (w->start, make_number (pos), Qnil);
+
+ /* Redisplay the lines where the text was changed */
+ last_text_vpos = vpos;
+ tab_offset = pos_tab_offset (w, pos);
+ /* If we are starting display in mid-character, correct tab_offset
+ to account for passing the line that that character really starts in. */
+ if (val.hpos < lmargin)
+ tab_offset += width;
+ while (vpos < stop_vpos)
+ {
+ val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
+ tab_offset += width;
+ if (val.vpos) tab_offset = 0;
+ if (pos != val.bufpos)
+ last_text_vpos
+ /* Next line, unless prev line ended in end of buffer with no cr */
+ = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
+ pos = val.bufpos;
+ }
+
+ /* There are two cases:
+ 1) we have displayed down to the bottom of the window
+ 2) we have scrolled lines below stop_vpos by scroll_amount */
+
+ if (vpos == height)
+ {
+ /* If last line is continued in middle of character,
+ include the split character in the text considered on the screen */
+ if (val.hpos < lmargin)
+ val.bufpos++;
+ XFASTINT (w->window_end_vpos) = last_text_vpos;
+ XFASTINT (w->window_end_pos) = Z - val.bufpos;
+ }
+
+ /* If scrolling made blank lines at window bottom,
+ redisplay to fill those lines */
+ if (scroll_amount < 0)
+ {
+ /* Don't consider these lines for general-purpose scrolling.
+ That will save time in the scrolling computation. */
+ SCREEN_SCROLL_BOTTOM_VPOS (s) = xp.vpos;
+ vpos = xp.vpos;
+ pos = xp.bufpos;
+ val.hpos = lmargin;
+ if (pos == ZV)
+ vpos = height + scroll_amount;
+ else if (xp.contin && xp.hpos != lmargin)
+ {
+ val.hpos = xp.prevhpos - width + lmargin;
+ pos--;
+ }
+
+ blank_end_of_window = 1;
+ tab_offset = pos_tab_offset (w, pos);
+ /* If we are starting display in mid-character, correct tab_offset
+ to account for passing the line that that character starts in. */
+ if (val.hpos < lmargin)
+ tab_offset += width;
+
+ while (vpos < height)
+ {
+ val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
+ tab_offset += width;
+ if (val.vpos) tab_offset = 0;
+ pos = val.bufpos;
+ }
+
+ /* Here is a case where display_text_line sets cursor_vpos wrong.
+ Make it be fixed up, below. */
+ if (xp.bufpos == ZV
+ && xp.bufpos == point)
+ cursor_vpos = -1;
+ }
+
+ /* If bottom just moved off end of screen, change mode line percentage. */
+ if (XFASTINT (w->window_end_pos) == 0
+ && Z != val.bufpos)
+ w->update_mode_line = Qt;
+
+ /* Attempt to adjust end-of-text positions to new bottom line */
+ if (scroll_amount)
+ {
+ delta = height - xp.vpos;
+ if (delta < 0
+ || (delta > 0 && xp.bufpos <= ZV)
+ || (delta == 0 && xp.hpos))
+ {
+ val = *vmotion (Z - XFASTINT (w->window_end_pos),
+ delta, width, hscroll, window);
+ XFASTINT (w->window_end_pos) = Z - val.bufpos;
+ XFASTINT (w->window_end_vpos) += val.vpos;
+ }
+ }
+
+ w->window_end_valid = Qnil;
+
+ /* If point was not in a line that was displayed, find it */
+ if (cursor_vpos < 0)
+ {
+ val = *compute_motion (start, 0, lmargin, point, 10000, 10000,
+ width, hscroll, pos_tab_offset (w, start));
+ /* Admit failure if point is off screen now */
+ if (val.vpos >= height)
+ {
+ for (vpos = 0; vpos < height; vpos++)
+ cancel_line (vpos + top, s);
+ return 0;
+ }
+ cursor_vpos = val.vpos + top;
+ cursor_hpos = val.hpos + XFASTINT (w->left);
+ }
+
+ SCREEN_CURSOR_X (s) = max (0, cursor_hpos);
+ SCREEN_CURSOR_Y (s) = cursor_vpos;
+
+ if (debug_end_pos)
+ {
+ val = *compute_motion (start, 0, lmargin, ZV,
+ height, - (1 << (SHORTBITS - 1)),
+ width, hscroll, pos_tab_offset (w, start));
+ if (val.vpos != XFASTINT (w->window_end_vpos))
+ abort ();
+ if (XFASTINT (w->window_end_pos)
+ != Z - val.bufpos)
+ abort ();
+ }
+
+ return 1;
+}
+
+/* Copy part of the contents of the string FROM into a glyph-vector at S.
+ But don't actually copy the parts that would come in before T.
+ Value is T, advanced past the copied data.
+
+ Characters in FROM are grouped into units of `sizeof GLYPH' chars;
+ any extra chars at the end of FROM are ignored. */
+
+GLYPH *
+copy_rope (t, s, from)
+ register GLYPH *t; /* Copy to here. */
+ register GLYPH *s; /* Starting point. */
+ Lisp_Object from; /* Data to copy; known to be a string. */
+{
+ register int n = XSTRING (from)->size / sizeof (GLYPH);
+ register GLYPH *f = (GLYPH *) XSTRING (from)->data;
+
+ while (n--)
+ {
+ if (t >= s) *t = *f;
+ ++t;
+ ++f;
+ }
+ return t;
+}
+
+/* Display one line of window w, starting at position START in W's buffer.
+ Display starting at horizontal position HPOS, which is normally zero
+ or negative. A negative value causes output up to hpos = 0 to be discarded.
+ This is done for negative hscroll, or when this is a continuation line
+ and the continuation occurred in the middle of a multi-column character.
+
+ TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
+
+ Display on position VPOS on the screen. (origin 0).
+
+ Returns a STRUCT POSITION giving character to start next line with
+ and where to display it, including a zero or negative hpos.
+ The vpos field is not really a vpos; it is 1 unless the line is continued */
+
+struct position val_display_text_line;
+
+static struct position *
+display_text_line (w, start, vpos, hpos, taboffset)
+ struct window *w;
+ int start;
+ int vpos;
+ int hpos;
+ int taboffset;
+{
+ register int pos = start;
+ register int c;
+ register GLYPH *p1;
+ int end;
+ register int pause;
+ register unsigned char *p;
+ GLYPH *endp;
+ register GLYPH *startp;
+ register GLYPH *p1prev;
+ SCREEN_PTR s = XSCREEN (w->screen);
+ int tab_width = XINT (current_buffer->tab_width);
+ int ctl_arrow = !NULL (current_buffer->ctl_arrow);
+ int width = XFASTINT (w->width) - 1
+ - (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s));
+ struct position val;
+ int lastpos;
+ int invis;
+ int hscroll = XINT (w->hscroll);
+ int truncate = hscroll
+ || (truncate_partial_width_windows
+ && XFASTINT (w->width) < SCREEN_WIDTH (s))
+ || !NULL (current_buffer->truncate_lines);
+ int selective
+ = XTYPE (current_buffer->selective_display) == Lisp_Int
+ ? XINT (current_buffer->selective_display)
+ : !NULL (current_buffer->selective_display) ? -1 : 0;
+#ifndef old
+ int selective_e = selective && !NULL (current_buffer->selective_display_ellipses);
+#endif
+ register struct screen_glyphs *desired_glyphs = SCREEN_DESIRED_GLYPHS (s);
+ register struct Lisp_Vector *dp = window_display_table (w);
+ int selective_rlen
+ = (selective && dp && XTYPE (DISP_INVIS_ROPE (dp)) == Lisp_String
+ ? XSTRING (DISP_INVIS_ROPE (dp))->size / sizeof (GLYPH) : 0);
+ GLYPH truncator = (dp == 0 || XTYPE (DISP_TRUNC_GLYPH (dp)) != Lisp_Int
+ ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
+ GLYPH continuer = (dp == 0 || XTYPE (DISP_CONTINUE_GLYPH (dp)) != Lisp_Int
+ ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
+
+ hpos += XFASTINT (w->left);
+ get_display_line (s, vpos, XFASTINT (w->left));
+ if (tab_width <= 0 || tab_width > 20) tab_width = 8;
+
+ if (MINI_WINDOW_P (w) && start == 1
+ && vpos == XFASTINT (w->top))
+ {
+ if (minibuf_prompt)
+ hpos = display_string (w, vpos, minibuf_prompt, hpos,
+ (!truncate ? continuer : truncator),
+ -1, -1);
+ minibuf_prompt_width = hpos;
+ }
+
+ desired_glyphs->bufp[vpos] = pos;
+ p1 = desired_glyphs->glyphs[vpos] + hpos;
+ end = ZV;
+ startp = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
+ endp = startp + width;
+
+ /* Loop generating characters.
+ Stop at end of buffer, before newline,
+ or if reach or pass continuation column. */
+
+ pause = pos;
+ while (p1 < endp)
+ {
+ p1prev = p1;
+ if (pos == pause)
+ {
+ if (pos == end)
+ break;
+ if (pos == point && cursor_vpos < 0)
+ {
+ cursor_vpos = vpos;
+ cursor_hpos = p1 - startp;
+ }
+
+ pause = end;
+ if (pos < point && point < pause)
+ pause = point;
+ if (pos < GPT && GPT < pause)
+ pause = GPT;
+
+ p = &FETCH_CHAR (pos);
+ }
+ c = *p++;
+ if (c >= 040 && c < 0177
+ && (dp == 0 || XTYPE (DISP_CHAR_ROPE (dp, c)) != Lisp_String))
+ {
+ if (p1 >= startp)
+ *p1 = c;
+ p1++;
+ }
+ else if (c == '\n')
+ {
+ invis = 0;
+ while (pos < end
+ && selective > 0
+ && position_indentation (pos + 1) >= selective)
+ {
+ invis = 1;
+ pos = find_next_newline (pos + 1, 1);
+ if (FETCH_CHAR (pos - 1) == '\n')
+ pos--;
+ }
+ if (invis && selective_rlen > 0 && p1 >= startp)
+ {
+ p1 += selective_rlen;
+ if (p1 - startp > width)
+ p1 = endp;
+ bcopy (XSTRING (DISP_INVIS_ROPE (dp))->data, p1prev,
+ (p1 - p1prev) * sizeof (GLYPH));
+ }
+ break;
+ }
+ else if (c == '\t')
+ {
+ do
+ {
+ if (p1 >= startp && p1 < endp)
+ *p1 = SPACEGLYPH;
+ p1++;
+ }
+ while ((p1 - startp + taboffset + hscroll - (hscroll > 0))
+ % tab_width);
+ }
+ else if (c == Ctl('M') && selective == -1)
+ {
+ pos = find_next_newline (pos, 1);
+ if (FETCH_CHAR (pos - 1) == '\n')
+ pos--;
+ if (selective_rlen > 0)
+ {
+ p1 += selective_rlen;
+ if (p1 - startp > width)
+ p1 = endp;
+ bcopy (XSTRING (DISP_INVIS_ROPE (dp))->data, p1prev,
+ (p1 - p1prev) * sizeof (GLYPH));
+ }
+ break;
+ }
+ else if (dp != 0 && XTYPE (DISP_CHAR_ROPE (dp, c)) == Lisp_String)
+ {
+ p1 = copy_rope (p1, startp, DISP_CHAR_ROPE (dp, c));
+ }
+ else if (c < 0200 && ctl_arrow)
+ {
+ if (p1 >= startp)
+ *p1 = (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
+ ? XINT (DISP_CTRL_GLYPH (dp)) : '^');
+ p1++;
+ if (p1 >= startp)
+ *p1 = c ^ 0100;
+ p1++;
+ }
+ else
+ {
+ if (p1 >= startp)
+ *p1 = (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
+ ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\');
+ p1++;
+ if (p1 >= startp)
+ *p1 = (c >> 6) + '0';
+ p1++;
+ if (p1 >= startp)
+ *p1 = (7 & (c >> 3)) + '0';
+ p1++;
+ if (p1 >= startp)
+ *p1 = (7 & c) + '0';
+ p1++;
+ }
+ pos++;
+ }
+
+ val.hpos = - XINT (w->hscroll);
+ if (val.hpos)
+ val.hpos++;
+
+ val.vpos = 1;
+
+ lastpos = pos;
+
+ /* Handle continuation in middle of a character */
+ /* by backing up over it */
+ if (p1 > endp)
+ {
+ /* Start the next line with that same character */
+ pos--;
+ /* but at a negative hpos, to skip the columns output on this line. */
+ val.hpos += p1prev - endp;
+ /* Keep in this line everything up to the continuation column. */
+ p1 = endp;
+ }
+
+ /* Finish deciding which character to start the next line on,
+ and what hpos to start it at.
+ Also set `lastpos' to the last position which counts as "on this line"
+ for cursor-positioning. */
+
+ if (pos < ZV)
+ {
+ if (FETCH_CHAR (pos) == '\n')
+ /* If stopped due to a newline, start next line after it */
+ pos++;
+ else
+ /* Stopped due to right margin of window */
+ {
+ if (truncate)
+ {
+ *p1++ = truncator;
+ /* Truncating => start next line after next newline,
+ and point is on this line if it is before the newline,
+ and skip none of first char of next line */
+ pos = find_next_newline (pos, 1);
+ val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
+
+ lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
+ }
+ else
+ {
+ *p1++ = continuer;
+ val.vpos = 0;
+ lastpos--;
+ }
+ }
+ }
+
+ /* If point is at eol or in invisible text at eol,
+ record its screen location now. */
+
+ if (start <= point && point <= lastpos && cursor_vpos < 0)
+ {
+ cursor_vpos = vpos;
+ cursor_hpos = p1 - startp;
+ }
+
+ if (cursor_vpos == vpos)
+ {
+ if (cursor_hpos < 0) cursor_hpos = 0;
+ if (cursor_hpos > width) cursor_hpos = width;
+ cursor_hpos += XFASTINT (w->left);
+ if (w == XWINDOW (SCREEN_SELECTED_WINDOW (s)))
+ {
+ SCREEN_CURSOR_Y (s) = cursor_vpos;
+ SCREEN_CURSOR_X (s) = cursor_hpos;
+
+ if (w == XWINDOW (selected_window))
+ {
+ /* Line is not continued and did not start
+ in middle of character */
+ if ((hpos - XFASTINT (w->left)
+ == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
+ && val.vpos)
+ {
+ this_line_bufpos = start;
+ this_line_buffer = current_buffer;
+ this_line_vpos = cursor_vpos;
+ this_line_start_hpos = hpos;
+ this_line_endpos = Z - lastpos;
+ }
+ else
+ this_line_bufpos = 0;
+ }
+ }
+ }
+
+ /* If hscroll and line not empty, insert truncation-at-left marker */
+ if (hscroll && lastpos != start)
+ {
+ *startp = truncator;
+ if (p1 <= startp)
+ p1 = startp + 1;
+ }
+
+ if (XFASTINT (w->width) + XFASTINT (w->left) != SCREEN_WIDTH (s))
+ {
+ endp++;
+ if (p1 < startp) p1 = startp;
+ while (p1 < endp) *p1++ = SPACEGLYPH;
+ *p1++ = '|';
+ }
+ desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
+ p1 - desired_glyphs->glyphs[vpos]);
+ desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
+
+ /* If the start of this line is the overlay arrow-position,
+ then put the arrow string into the display-line. */
+
+ if (XTYPE (Voverlay_arrow_position) == Lisp_Marker
+ && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
+ && start == marker_position (Voverlay_arrow_position)
+ && XTYPE (Voverlay_arrow_string) == Lisp_String
+ && ! overlay_arrow_seen)
+ {
+ unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
+ int i;
+ int len = XSTRING (Voverlay_arrow_string)->size;
+
+ if (len > XFASTINT (w->width) - 1)
+ len = XFASTINT (w->width) - 1;
+ for (i = 0; i < len; i++)
+ startp[i] = p[i];
+ if (desired_glyphs->used[vpos] <
+ (len + startp - desired_glyphs->glyphs[vpos]))
+ desired_glyphs->used[vpos] = len + startp - desired_glyphs->glyphs[vpos];
+
+ overlay_arrow_seen = 1;
+ }
+
+ val.bufpos = pos;
+ val_display_text_line = val;
+ return &val_display_text_line;
+}
+
+/* Display the mode line for window w */
+
+static void
+display_mode_line (w)
+ struct window *w;
+{
+ register int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
+ register int left = XFASTINT (w->left);
+ register int right = XFASTINT (w->width) + left;
+ register SCREEN_PTR s = XSCREEN (WINDOW_SCREEN (w));
+
+ get_display_line (s, vpos, left);
+ display_mode_element (w, vpos, left, 0, right, right,
+ current_buffer->mode_line_format);
+ SCREEN_DESIRED_GLYPHS (s)->bufp[vpos] = 0;
+
+ /* Make the mode line inverse video if the entire line
+ is made of mode lines.
+ I.e. if this window is full width,
+ or if it is the child of a full width window
+ (which implies that that window is split side-by-side
+ and the rest of this line is mode lines of the sibling windows). */
+ if (XFASTINT (w->width) == SCREEN_WIDTH (s)
+ || XFASTINT (XWINDOW (w->parent)->width) == SCREEN_WIDTH (s))
+ s->desired_glyphs->highlight[vpos] = mode_line_inverse_video;
+
+#ifdef HAVE_X_WINDOWS
+ /* I'm trying this out because I saw Unimpress use it, but it's
+ possible that this may fuck adversely with some window managers. jla */
+
+ if (SCREEN_IS_X (s)
+ && (XTYPE (Vglobal_minibuffer_screen) != Lisp_Screen
+ || s != XSCREEN (Vglobal_minibuffer_screen))
+ && w == XWINDOW (s->selected_window)
+ && (NULL (Fstring_equal (XBUFFER (w->buffer)->name, s->name))))
+ x_set_name (s, XBUFFER (w->buffer)->name, Qnil);
+#endif
+}
+
+/* Contribute ELT to the mode line for window W.
+ How it translates into text depends on its data type.
+
+ VPOS is the position of the mode line being displayed.
+
+ HPOS is the position (absolute on screen) where this element's text
+ should start. The output is truncated automatically at the right
+ edge of window W.
+
+ DEPTH is the depth in recursion. It is used to prevent
+ infinite recursion here.
+
+ MINENDCOL is the hpos before which the element may not end.
+ The element is padded at the right with spaces if nec
+ to reach this column.
+
+ MAXENDCOL is the hpos past which this element may not extend.
+ If MINENDCOL is > MAXENDCOL, MINENDCOL takes priority.
+ (This is necessary to make nested padding and truncation work.)
+
+ Returns the hpos of the end of the text generated by ELT.
+ The next element will receive that value as its HPOS arg,
+ so as to concatenate the elements. */
+
+static int
+display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
+ struct window *w;
+ register int vpos, hpos;
+ int depth;
+ int minendcol;
+ register int maxendcol;
+ register Lisp_Object elt;
+{
+ tail_recurse:
+ if (depth > 10)
+ goto invalid;
+
+ depth++;
+
+#ifdef SWITCH_ENUM_BUG
+ switch ((int) XTYPE (elt))
+#else
+ switch (XTYPE (elt))
+#endif
+ {
+ case Lisp_String:
+ {
+ /* A string: output it and check for %-constructs within it. */
+ register unsigned char c;
+ register unsigned char *this = XSTRING (elt)->data;
+
+ while (hpos < maxendcol && *this)
+ {
+ unsigned char *last = this;
+ while ((c = *this++) != '\0' && c != '%')
+ ;
+ if (this - 1 != last)
+ {
+ register int lim = --this - last + hpos;
+ hpos = display_string (w, vpos, last, hpos, 0, hpos,
+ min (lim, maxendcol));
+ }
+ else /* c == '%' */
+ {
+ register int spec_width = 0;
+
+ /* We can't allow -ve args due to the "%-" construct */
+ /* Argument specifies minwidth but not maxwidth
+ (maxwidth can be specified by
+ (<negative-number> . <stuff>) mode-line elements) */
+
+ while ((c = *this++) >= '0' && c <= '9')
+ {
+ spec_width = spec_width * 10 + (c - '0');
+ }
+
+ spec_width += hpos;
+ if (spec_width > maxendcol)
+ spec_width = maxendcol;
+
+ if (c == 'M')
+ hpos = display_mode_element (w, vpos, hpos, depth,
+ spec_width, maxendcol,
+ Vglobal_mode_string);
+ else if (c != 0)
+ hpos = display_string (w, vpos,
+ decode_mode_spec (w, c,
+ maxendcol - hpos),
+ hpos, 0, spec_width, maxendcol);
+ }
+ }
+ }
+ break;
+
+ case Lisp_Symbol:
+ /* A symbol: process the value of the symbol recursively
+ as if it appeared here directly. Avoid error if symbol void.
+ Special case: if value of symbol is a string, output the string
+ literally. */
+ {
+ register Lisp_Object tem;
+ tem = Fboundp (elt);
+ if (!NULL (tem))
+ {
+ tem = Fsymbol_value (elt);
+ /* If value is a string, output that string literally:
+ don't check for % within it. */
+ if (XTYPE (tem) == Lisp_String)
+ hpos = display_string (w, vpos, XSTRING (tem)->data,
+ hpos, 0, minendcol, maxendcol);
+ /* Give up right away for nil or t. */
+ else if (!EQ (tem, elt))
+ { elt = tem; goto tail_recurse; }
+ }
+ }
+ break;
+
+ case Lisp_Cons:
+ {
+ register Lisp_Object car, tem;
+
+ /* A cons cell: three distinct cases.
+ If first element is a string or a cons, process all the elements
+ and effectively concatenate them.
+ If first element is a negative number, truncate displaying cdr to
+ at most that many characters. If positive, pad (with spaces)
+ to at least that many characters.
+ If first element is a symbol, process the cadr or caddr recursively
+ according to whether the symbol's value is non-nil or nil. */
+ car = XCONS (elt)->car;
+ if (XTYPE (car) == Lisp_Symbol)
+ {
+ tem = Fboundp (car);
+ elt = XCONS (elt)->cdr;
+ if (XTYPE (elt) != Lisp_Cons)
+ goto invalid;
+ /* elt is now the cdr, and we know it is a cons cell.
+ Use its car if CAR has a non-nil value. */
+ if (!NULL (tem))
+ {
+ tem = Fsymbol_value (car);
+ if (!NULL (tem))
+ { elt = XCONS (elt)->car; goto tail_recurse; }
+ }
+ /* Symbol's value is nil (or symbol is unbound)
+ Get the cddr of the original list
+ and if possible find the caddr and use that. */
+ elt = XCONS (elt)->cdr;
+ if (NULL (elt))
+ break;
+ else if (XTYPE (elt) != Lisp_Cons)
+ goto invalid;
+ elt = XCONS (elt)->car;
+ goto tail_recurse;
+ }
+ else if (XTYPE (car) == Lisp_Int)
+ {
+ register int lim = XINT (car);
+ elt = XCONS (elt)->cdr;
+ if (lim < 0)
+ /* Negative int means reduce maximum width.
+ DO NOT change MINENDCOL here!
+ (20 -10 . foo) should truncate foo to 10 col
+ and then pad to 20. */
+ maxendcol = min (maxendcol, hpos - lim);
+ else if (lim > 0)
+ {
+ /* Padding specified. Don't let it be more than
+ current maximum. */
+ lim += hpos;
+ if (lim > maxendcol)
+ lim = maxendcol;
+ /* If that's more padding than already wanted, queue it.
+ But don't reduce padding already specified even if
+ that is beyond the current truncation point. */
+ if (lim > minendcol)
+ minendcol = lim;
+ }
+ goto tail_recurse;
+ }
+ else if (XTYPE (car) == Lisp_String || XTYPE (car) == Lisp_Cons)
+ {
+ register int limit = 50;
+ /* LIMIT is to protect against circular lists. */
+ while (XTYPE (elt) == Lisp_Cons && --limit > 0
+ && hpos < maxendcol)
+ {
+ hpos = display_mode_element (w, vpos, hpos, depth,
+ hpos, maxendcol,
+ XCONS (elt)->car);
+ elt = XCONS (elt)->cdr;
+ }
+ }
+ }
+ break;
+
+ default:
+ invalid:
+ return (display_string (w, vpos, "*invalid*", hpos, 0,
+ minendcol, maxendcol));
+ }
+
+ end:
+ if (minendcol > hpos)
+ hpos = display_string (w, vpos, "", hpos, 0, minendcol, -1);
+ return hpos;
+}
+
+/* Return a string for the output of a mode line %-spec for window W,
+ generated by character C and width MAXWIDTH. */
+
+static char *
+decode_mode_spec (w, c, maxwidth)
+ struct window *w;
+ register char c;
+ register int maxwidth;
+{
+ Lisp_Object obj = Qnil;
+ SCREEN_PTR scr = XSCREEN (WINDOW_SCREEN (w));
+ char *decode_mode_spec_buf = (char *) SCREEN_TEMP_GLYPHS (scr)->total_contents;
+
+ if (maxwidth > SCREEN_WIDTH (scr))
+ maxwidth = SCREEN_WIDTH (scr);
+
+ switch (c)
+ {
+ case 'b':
+ obj = current_buffer->name;
+#if 0
+ if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
+ {
+ bcopy (XSTRING (obj)->data, decode_mode_spec_buf, maxwidth - 1);
+ decode_mode_spec_buf[maxwidth - 1] = '\\';
+ decode_mode_spec_buf[maxwidth] = '\0';
+ return decode_mode_spec_buf;
+ }
+#endif
+ break;
+
+ case 'f':
+ obj = current_buffer->filename;
+#if 0
+ if (NULL (obj))
+ return "[none]";
+ else if (XTYPE (obj) == Lisp_String && XSTRING (obj)->size > maxwidth)
+ {
+ bcopy ("...", decode_mode_spec_buf, 3);
+ bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
+ decode_mode_spec_buf + 3, maxwidth - 3);
+ return decode_mode_spec_buf;
+ }
+#endif
+ break;
+
+ case 'm':
+ obj = current_buffer->mode_name;
+ break;
+
+ case 'n':
+ if (BEGV > BEG || ZV < Z)
+ return " Narrow";
+ break;
+
+ case '*':
+ if (!NULL (current_buffer->read_only))
+ return "%";
+ if (MODIFF > current_buffer->save_modified)
+ return "*";
+ return "-";
+
+ case 's':
+ /* status of process */
+#ifdef subprocesses
+ obj = Fget_buffer_process (Fcurrent_buffer ());
+ if (NULL (obj))
+ return "no process";
+ obj = Fsymbol_name (Fprocess_status (obj));
+ break;
+#else
+ return "no processes";
+#endif /* subprocesses */
+
+ case 'p':
+ {
+ int pos = marker_position (w->start);
+ int total = ZV - BEGV;
+
+ if (XFASTINT (w->window_end_pos) <= Z - ZV)
+ {
+ if (pos <= BEGV)
+ return "All";
+ else
+ return "Bottom";
+ }
+ else if (pos <= BEGV)
+ return "Top";
+ else
+ {
+ total = ((pos - BEGV) * 100 + total - 1) / total;
+ /* We can't normally display a 3-digit number,
+ so get us a 2-digit number that is close. */
+ if (total == 100)
+ total = 99;
+ sprintf (decode_mode_spec_buf, "%2d%%", total);
+ return decode_mode_spec_buf;
+ }
+ }
+
+ case '%':
+ return "%";
+
+ case '[':
+ {
+ int i;
+ char *p;
+
+ if (command_loop_level > 5)
+ return "[[[... ";
+ p = decode_mode_spec_buf;
+ for (i = 0; i < command_loop_level; i++)
+ *p++ = '[';
+ *p = 0;
+ return decode_mode_spec_buf;
+ }
+
+ case ']':
+ {
+ int i;
+ char *p;
+
+ if (command_loop_level > 5)
+ return " ...]]]";
+ p = decode_mode_spec_buf;
+ for (i = 0; i < command_loop_level; i++)
+ *p++ = ']';
+ *p = 0;
+ return decode_mode_spec_buf;
+ }
+
+ case '-':
+ {
+ static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
+ register char *p;
+ register int i;
+
+ if (maxwidth < sizeof (lots_of_dashes))
+ return lots_of_dashes;
+ else
+ {
+ for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
+ *p++ = '-';
+ *p = '\0';
+ }
+ return decode_mode_spec_buf;
+ }
+ }
+
+ if (XTYPE (obj) == Lisp_String)
+ return (char *) XSTRING (obj)->data;
+ else
+ return "";
+}
+
+/* Display STRING on one line of window W, starting at HPOS.
+ Display at position VPOS. Caller should have done get_display_line.
+
+ TRUNCATE is GLYPH to display at end if truncated. Zero for none.
+
+ MINCOL is the first column ok to end at. (Pad with spaces to this col.)
+ MAXCOL is the last column ok to end at. Truncate here.
+ -1 for MINCOL or MAXCOL means no explicit minimum or maximum.
+ Both count from the left edge of the screen, as does HPOS.
+ The right edge of W is an implicit maximum.
+ If TRUNCATE is nonzero, the implicit maximum is one column before the edge.
+
+ Returns ending hpos */
+
+static int
+display_string (w, vpos, string, hpos, truncate, mincol, maxcol)
+ struct window *w;
+ unsigned char *string;
+ int vpos, hpos;
+ GLYPH truncate;
+ int mincol, maxcol;
+{
+ register int c;
+ register GLYPH *p1;
+ int hscroll = XINT (w->hscroll);
+ int tab_width = XINT (current_buffer->tab_width);
+ register GLYPH *start;
+ register GLYPH *end;
+ struct screen_glyphs *desired_glyphs = SCREEN_DESIRED_GLYPHS (XSCREEN (w->screen));
+ GLYPH *p1start = desired_glyphs->glyphs[vpos] + hpos;
+ int window_width = XFASTINT (w->width);
+
+ /* Use the standard display table, not the window's display table.
+ We don't want the mode line in rot13. */
+ register struct Lisp_Vector *dp = 0;
+
+ if (XTYPE (Vstandard_display_table) == Lisp_Vector
+ && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
+ dp = XVECTOR (Vstandard_display_table);
+
+ if (tab_width <= 0 || tab_width > 20) tab_width = 8;
+
+ p1 = p1start;
+ start = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
+ end = start + window_width - (truncate != 0);
+
+ if ((window_width + XFASTINT (w->left))
+ != SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w))))
+ *end-- = '|';
+
+ if (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol)
+ end = desired_glyphs->glyphs[vpos] + maxcol;
+ if (maxcol >= 0 && mincol > maxcol)
+ mincol = maxcol;
+
+ while (p1 < end)
+ {
+ c = *string++;
+ if (!c) break;
+ if (c >= 040 && c < 0177
+ && (dp == 0 || XTYPE (DISP_CHAR_ROPE (dp, c)) != Lisp_String))
+ {
+ if (p1 >= start)
+ *p1 = c;
+ p1++;
+ }
+ else if (c == '\t')
+ {
+ do
+ {
+ if (p1 >= start && p1 < end)
+ *p1 = SPACEGLYPH;
+ p1++;
+ }
+ while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
+ }
+ else if (dp != 0 && XTYPE (DISP_CHAR_ROPE (dp, c)) == Lisp_String)
+ p1 = copy_rope (p1, start, DISP_CHAR_ROPE (dp, c));
+ else if (c < 0200 && buffer_defaults.ctl_arrow)
+ {
+ if (p1 >= start)
+ *p1 = (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
+ ? XINT (DISP_CTRL_GLYPH (dp)) : '^');
+ p1++;
+ if (p1 >= start)
+ *p1 = c ^ 0100;
+ p1++;
+ }
+ else
+ {
+ if (p1 >= start)
+ *p1 = (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
+ ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\');
+ p1++;
+ if (p1 >= start)
+ *p1 = (c >> 6) + '0';
+ p1++;
+ if (p1 >= start)
+ *p1 = (7 & (c >> 3)) + '0';
+ p1++;
+ if (p1 >= start)
+ *p1 = (7 & c) + '0';
+ p1++;
+ }
+ }
+
+ if (c)
+ {
+ p1 = end;
+ if (truncate) *p1++ = truncate;
+ }
+ else if (mincol >= 0)
+ {
+ end = desired_glyphs->glyphs[vpos] + mincol;
+ while (p1 < end)
+ *p1++ = SPACEGLYPH;
+ }
+
+ {
+ register int len = p1 - desired_glyphs->glyphs[vpos];
+
+ if (len > desired_glyphs->used[vpos])
+ desired_glyphs->used[vpos] = len;
+ desired_glyphs->glyphs[vpos][desired_glyphs->used[vpos]] = 0;
+
+ return len;
+ }
+}
+
+void
+syms_of_xdisp ()
+{
+ staticpro (&last_arrow_position);
+ staticpro (&last_arrow_string);
+ last_arrow_position = Qnil;
+ last_arrow_string = Qnil;
+
+ DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
+ "String displayed by mode-line-format's \"%m\" specifiation.");
+ Vglobal_mode_string = Qnil;
+
+ DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
+ "Marker for where to display an arrow on top of the buffer text.\n\
+This must be the beginning of a line in order to work.\n\
+See also `overlay-arrow-string'.");
+ Voverlay_arrow_position = Qnil;
+
+ DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
+ "String to display as an arrow. See also `overlay-arrow-position'.");
+ Voverlay_arrow_string = Qnil;
+
+ DEFVAR_INT ("scroll-step", &scroll_step,
+ "*The number of lines to try scrolling a window by when point moves out.\n\
+If that fails to bring point back on screen, point is centered instead.\n\
+If this is zero, point is always centered after it moves off screen.");
+
+ DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
+
+ DEFVAR_BOOL ("truncate-partial-width-windows",
+ &truncate_partial_width_windows,
+ "*Non-nil means truncate lines in all windows less than full screen wide.");
+ truncate_partial_width_windows = 1;
+
+ DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
+ "*Non-nil means use inverse video for the mode line.");
+ mode_line_inverse_video = 1;
+
+#ifndef MULTI_SCREEN
+ defsubr (&Sredraw_display);
+#endif /* MULTI_SCREEN */
+}
+
+/* initialize the window system */
+init_xdisp ()
+{
+ Lisp_Object root_window;
+#ifndef COMPILER_REGISTER_BUG
+ register
+#endif /* COMPILER_REGISTER_BUG */
+ struct window *mini_w;
+
+ this_line_bufpos = 0;
+
+ mini_w = XWINDOW (minibuf_window);
+ root_window = mini_w->prev;
+
+ echo_area_glyphs = 0;
+ previous_echo_glyphs = 0;
+
+ if (!noninteractive)
+ {
+ SCREEN_PTR s = XSCREEN (WINDOW_SCREEN (XWINDOW (root_window)));
+ XFASTINT (XWINDOW (root_window)->top) = 0;
+ set_window_height (root_window, SCREEN_HEIGHT (s) - 1, 0);
+ XFASTINT (mini_w->top) = SCREEN_HEIGHT (s) - 1;
+ set_window_height (minibuf_window, 1, 0);
+
+ XFASTINT (XWINDOW (root_window)->width) = SCREEN_WIDTH (s);
+ XFASTINT (mini_w->width) = SCREEN_WIDTH (s);
+ }
+}