/* Display generation from window structure and buffer text.
- Copyright (C) 1985, 1986, 1987, 1988, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1985, 86, 87, 88, 93, 94 Free Software Foundation, Inc.
This file is part of GNU Emacs.
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include "config.h"
+#include <config.h>
#include <stdio.h>
/*#include <ctype.h>*/
#undef NULL
#include "macros.h"
#include "disptab.h"
#include "termhooks.h"
+#include "intervals.h"
+
+#ifdef USE_X_TOOLKIT
+extern void set_frame_menubar ();
+#endif
extern int interrupt_input;
extern int command_loop_level;
+extern Lisp_Object Qface;
+
/* Nonzero means print newline before next minibuffer message. */
int noninteractive_need_newline;
/* Nonzero means truncate lines in all windows less wide than the frame */
int truncate_partial_width_windows;
+/* Nonzero means we have more than one non-minibuffer-only frame.
+ Not guaranteed to be accurate except while parsing frame-title-format. */
+int multiple_frames;
+
Lisp_Object Vglobal_mode_string;
/* Marker for where to display an arrow on top of the buffer text. */
/* String to display for the arrow. */
Lisp_Object Voverlay_arrow_string;
+/* Like mode-line-format, but for the titlebar on a visible frame. */
+Lisp_Object Vframe_title_format;
+
+/* Like mode-line-format, but for the titlebar on an iconified frame. */
+Lisp_Object Vicon_title_format;
+
/* Values of those variables at last redisplay. */
static Lisp_Object last_arrow_position, last_arrow_string;
+Lisp_Object Qmenu_bar_update_hook;
+
/* Nonzero if overlay arrow has been displayed once in this window. */
static int overlay_arrow_seen;
+/* Nonzero means highlight the region even in nonselected windows. */
+static int highlight_nonselected_windows;
+
/* If cursor motion alone moves point off frame,
Try scrolling this many lines up or down if that will bring it back. */
int scroll_step;
void mark_window_display_accurate ();
static void redisplay_windows ();
static void redisplay_window ();
+static void update_menu_bars ();
+static void update_menu_bar ();
static void try_window ();
static int try_window_id ();
static struct position *display_text_line ();
static char *decode_mode_spec ();
static int display_string ();
static void display_menu_bar ();
+static int display_count_lines ();
/* Prompt to display in front of the minibuffer contents */
-char *minibuf_prompt;
+Lisp_Object minibuf_prompt;
/* Width in columns of current minibuffer prompt. */
int minibuf_prompt_width;
It overrides the minibuf_prompt as well as the buffer. */
char *echo_area_glyphs;
+/* This is the length of the message in echo_area_glyphs. */
+int echo_area_glyphs_length;
+
/* true iff we should redraw the mode lines on the next redisplay */
int update_mode_lines;
since last redisplay that finished */
int windows_or_buffers_changed;
+/* Nonzero after display_mode_line if %l was used
+ and it displayed a line number. */
+int line_number_displayed;
+
+/* Maximum buffer size for which to display line numbers. */
+int line_number_display_limit;
\f
-/* Specify m, a string, as a message in the minibuf. If m is 0, clear out
- any existing message, and let the minibuffer text show through. */
+/* Display an echo area message M with a specified length of LEN chars.
+ The string may include null characters. If m is 0, clear out any
+ existing message, and let the minibuffer text show through.
+ Do not pass text that is stored in a Lisp string. */
+
void
-message1 (m)
+message2 (m, len)
char *m;
+ int len;
{
if (noninteractive)
{
if (noninteractive_need_newline)
putc ('\n', stderr);
noninteractive_need_newline = 0;
- fprintf (stderr, "%s\n", m);
+ fwrite (m, len, 1, stderr);
+ if (cursor_in_echo_area == 0)
+ fprintf (stderr, "\n");
fflush (stderr);
}
/* A null message buffer means that the frame hasn't really been
#endif
if (m)
- echo_area_glyphs = m;
+ {
+ echo_area_glyphs = m;
+ echo_area_glyphs_length = len;
+ }
else
echo_area_glyphs = previous_echo_glyphs = 0;
echo_area_display ();
update_frame (XFRAME (XWINDOW (minibuf_window)->frame), 1, 1);
do_pending_window_change ();
+ if (frame_up_to_date_hook != 0 && ! gc_in_progress)
+ (*frame_up_to_date_hook) (XFRAME (XWINDOW (minibuf_window)->frame));
}
}
+void
+message1 (m)
+ char *m;
+{
+ message2 (m, (m ? strlen (m) : 0));
+}
+
+/* Truncate what will be displayed in the echo area
+ the next time we display it--but don't redisplay it now. */
+
+void
+truncate_echo_area (len)
+ int len;
+{
+ /* A null message buffer means that the frame hasn't really been
+ initialized yet. Error messages get reported properly by
+ cmd_error, so this must be just an informative message; toss it. */
+ if (!noninteractive && INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame))
+ echo_area_glyphs_length = len;
+}
+
/* Nonzero if FRAME_MESSAGE_BUF (selected_frame) is being used by print;
zero if being used by message. */
int message_buf_print;
void
message (m, a1, a2, a3)
char *m;
+ EMACS_INT a1, a2, a3;
{
if (noninteractive)
{
putc ('\n', stderr);
noninteractive_need_newline = 0;
fprintf (stderr, m, a1, a2, a3);
- fprintf (stderr, "\n");
+ if (cursor_in_echo_area == 0)
+ fprintf (stderr, "\n");
fflush (stderr);
}
}
{
if (m)
{
- {
+ int len;
#ifdef NO_ARG_ARRAY
- int a[3];
- a[0] = a1;
- a[1] = a2;
- a[2] = a3;
+ EMACS_INT a[3];
+ a[0] = a1;
+ a[1] = a2;
+ a[2] = a3;
- doprnt (FRAME_MESSAGE_BUF (echo_frame),
- FRAME_WIDTH (echo_frame), m, 0, 3, a);
+ len = doprnt (FRAME_MESSAGE_BUF (echo_frame),
+ FRAME_WIDTH (echo_frame), m, 0, 3, a);
#else
- doprnt (FRAME_MESSAGE_BUF (echo_frame),
- FRAME_WIDTH (echo_frame), m, 0, 3, &a1);
+ len = doprnt (FRAME_MESSAGE_BUF (echo_frame),
+ FRAME_WIDTH (echo_frame), m, 0, 3, &a1);
#endif /* NO_ARG_ARRAY */
- }
- message1 (FRAME_MESSAGE_BUF (echo_frame));
+ message2 (FRAME_MESSAGE_BUF (echo_frame), len);
}
else
message1 (0);
}
}
+void
+update_echo_area ()
+{
+ message2 (echo_area_glyphs, echo_area_glyphs_length);
+}
+
static void
echo_area_display ()
{
if (frame_garbaged)
{
- Fredraw_display ();
+ redraw_garbaged_frames ();
frame_garbaged = 0;
}
get_display_line (f, vpos, 0);
display_string (XWINDOW (minibuf_window), vpos,
echo_area_glyphs ? echo_area_glyphs : "",
- 0, 0, 0, FRAME_WIDTH (f));
+ echo_area_glyphs ? echo_area_glyphs_length : -1,
+ 0, 0, 0, 0, FRAME_WIDTH (f));
/* If desired cursor location is on this line, put it at end of text */
if (FRAME_CURSOR_Y (f) == vpos)
{
int i;
- for (i = vpos + 1; i < vpos + XWINDOW (minibuf_window)->height; i++)
+ for (i = vpos + 1;
+ i < vpos + XFASTINT (XWINDOW (minibuf_window)->height); i++)
{
get_display_line (f, i, 0);
display_string (XWINDOW (minibuf_window), vpos,
- "", 0, 0, 0, FRAME_WIDTH (f));
+ "", 0, 0, 0, 0, 0, FRAME_WIDTH (f));
}
}
}
previous_echo_glyphs = echo_area_glyphs;
}
+
+#ifdef HAVE_X_WINDOWS
+static char frame_title_buf[512];
+static char *frame_title_ptr;
+
+static int
+store_frame_title (str, mincol, maxcol)
+ char *str;
+ int mincol, maxcol;
+{
+ char *limit;
+ if (maxcol < 0 || maxcol >= sizeof(frame_title_buf))
+ maxcol = sizeof (frame_title_buf);
+ limit = &frame_title_buf[maxcol];
+ while (*str != '\0' && frame_title_ptr < limit)
+ *frame_title_ptr++ = *str++;
+ while (frame_title_ptr < &frame_title_buf[mincol])
+ *frame_title_ptr++ = ' ';
+ return frame_title_ptr - frame_title_buf;
+}
+
+static void
+x_consider_frame_title (frame)
+ Lisp_Object frame;
+{
+ Lisp_Object fmt;
+ struct buffer *obuf;
+ int len;
+ FRAME_PTR f = XFRAME (frame);
+
+ if (!FRAME_X_P (f) || FRAME_MINIBUF_ONLY_P (f) || f->explicit_name)
+ return;
+ multiple_frames = !EQ (Fnext_frame (frame, Qnil), frame);
+ obuf = current_buffer;
+ Fset_buffer (XWINDOW (f->selected_window)->buffer);
+ fmt = (FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format);
+ frame_title_ptr = frame_title_buf;
+ len = display_mode_element (XWINDOW (f->selected_window), 0, 0, 0,
+ 0, sizeof (frame_title_buf), fmt);
+ frame_title_ptr = 0;
+ set_buffer_internal (obuf);
+ /* Set the name only if it's changed. This avoids consing
+ in the common case where it hasn't. (If it turns out that we've
+ already wasted too much time by walking through the list with
+ display_mode_element, then we might need to optimize at a higher
+ level than this.) */
+ if (! STRINGP (f->name) || XSTRING (f->name)->size != len
+ || bcmp (frame_title_buf, XSTRING (f->name)->data, len) != 0)
+ x_implicitly_set_name (f, make_string (frame_title_buf, len), Qnil);
+}
+#else
+#define frame_title_ptr ((char *)0)
+#define store_frame_title(str, mincol, maxcol) 0
+#endif
+\f
+/* Prepare for redisplay by updating menu-bar item lists when appropriate.
+ This can't be done in `redisplay' itself because it can call eval. */
+
+void
+prepare_menu_bars ()
+{
+ register struct window *w = XWINDOW (selected_window);
+ int all_windows;
+
+ if (noninteractive)
+ return;
+
+ /* Set the visible flags for all frames.
+ Do this before checking for resized or garbaged frames; they want
+ to know if their frames are visible.
+ See the comment in frame.h for FRAME_SAMPLE_VISIBILITY. */
+ {
+ Lisp_Object tail, frame;
+
+ FOR_EACH_FRAME (tail, frame)
+ FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+ }
+
+ /* Notice any pending interrupt request to change frame size. */
+ do_pending_window_change ();
+
+ if (frame_garbaged)
+ {
+ redraw_garbaged_frames ();
+ frame_garbaged = 0;
+ }
+
+ all_windows = (update_mode_lines || buffer_shared > 1
+ || clip_changed || windows_or_buffers_changed);
+
+#ifdef HAVE_X_WINDOWS
+ if (windows_or_buffers_changed)
+ {
+ Lisp_Object tail, frame;
+
+ FOR_EACH_FRAME (tail, frame)
+ if (FRAME_VISIBLE_P (XFRAME (frame))
+ || FRAME_ICONIFIED_P (XFRAME (frame)))
+ x_consider_frame_title (frame);
+ }
+#endif
+
+ /* Update the menu bar item lists, if appropriate.
+ This has to be done before any actual redisplay
+ or generation of display lines. */
+ if (all_windows)
+ {
+ Lisp_Object tail, frame;
+
+ FOR_EACH_FRAME (tail, frame)
+ update_menu_bar (XFRAME (frame));
+ }
+ else
+ update_menu_bar (selected_frame);
+}
\f
/* Do a frame update, taking possible shortcuts into account.
This is the main external entry point for redisplay.
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;
+ Do not call eval from within this function.
+ Calls to eval after the call to echo_area_display would confuse
+ the display_line mechanism and would cause a crash.
+ Calls to eval before that point will work most of the time,
+ but can still lose, because this function
+ 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. */
+static int do_verify_charstarts;
+
void
redisplay ()
{
if (frame_garbaged)
{
- Fredraw_display ();
+ redraw_garbaged_frames ();
frame_garbaged = 0;
}
- /* Normally the message* functions will have already displayed and
- updated the echo area, but the frame may have been trashed, or
- the update may have been preempted, so display the echo area
- again here. */
- if (echo_area_glyphs || previous_echo_glyphs)
- {
- echo_area_display ();
- must_finish = 1;
- }
-
if (clip_changed || windows_or_buffers_changed)
update_mode_lines++;
|| ! EQ (Voverlay_arrow_string, last_arrow_string))
all_windows = 1, clip_changed = 1;
+ /* Normally the message* functions will have already displayed and
+ updated the echo area, but the frame may have been trashed, or
+ the update may have been preempted, so display the echo area
+ again here. */
+ if (echo_area_glyphs || previous_echo_glyphs)
+ {
+ echo_area_display ();
+ must_finish = 1;
+ }
+
+ /* If showing region, and mark has changed, must redisplay whole window. */
+ if (((!NILP (Vtransient_mark_mode)
+ && !NILP (XBUFFER (w->buffer)->mark_active))
+ != !NILP (w->region_showing))
+ || (!NILP (w->region_showing)
+ && !EQ (w->region_showing,
+ Fmarker_position (XBUFFER (w->buffer)->mark))))
+ this_line_bufpos = -1;
+
tlbufpos = this_line_bufpos;
tlendpos = this_line_endpos;
if (!all_windows && tlbufpos > 0 && NILP (w->update_mode_line)
&& current_buffer == XBUFFER (w->buffer)
&& NILP (w->force_start)
/* Point must be on the line that we have info recorded about */
- && point >= tlbufpos
- && point <= Z - tlendpos
+ && PT >= tlbufpos
+ && PT <= Z - tlendpos
/* All text outside that line, including its final newline,
must be unchanged */
&& (XFASTINT (w->last_modified) >= MODIFF
&& GPT >= tlbufpos
/* If selective display, can't optimize
if the changes start at the beginning of the line. */
- && ((XTYPE (current_buffer->selective_display) == Lisp_Int
+ && ((INTEGERP (current_buffer->selective_display)
&& XINT (current_buffer->selective_display) > 0
? (beg_unchanged >= tlbufpos
&& GPT > tlbufpos)
if (cursor_vpos >= 0 && this_line_bufpos
&& this_line_endpos == tlendpos)
{
+ /* If this is not the window's last line,
+ we must adjust the charstarts of the lines below. */
+ if (this_line_vpos + 1
+ < XFASTINT (w->top) + window_internal_height (w))
+ {
+ int left = XFASTINT (w->left);
+ int *charstart_next_line
+ = FRAME_CURRENT_GLYPHS (XFRAME (WINDOW_FRAME (w)))->charstarts[this_line_vpos + 1];
+ int i;
+ int adjust;
+
+ if (Z - tlendpos == ZV)
+ /* This line ends at end of (accessible part of) buffer.
+ There is no newline to count. */
+ adjust = Z - tlendpos - charstart_next_line[left];
+ else
+ /* This line ends in a newline.
+ Must take account of the newline and the rest of the
+ text that follows. */
+ adjust = Z - tlendpos + 1 - charstart_next_line[left];
+
+ adjust_window_charstarts (w, this_line_vpos, adjust);
+ }
+
if (XFASTINT (w->width) != FRAME_WIDTH (XFRAME (WINDOW_FRAME (w))))
preserve_other_columns (w);
goto update;
else
goto cancel;
}
- else if (point == XFASTINT (w->last_point))
+ else if (PT == XFASTINT (w->last_point))
{
if (!must_finish)
{
}
goto update;
}
- else
+ /* If highlighting the region, we can't just move the cursor. */
+ else if (! (!NILP (Vtransient_mark_mode)
+ && !NILP (current_buffer->mark_active))
+ && NILP (w->region_showing))
{
pos = *compute_motion (tlbufpos, 0,
XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
- point, 2, - (1 << (SHORTBITS - 1)),
+ PT, 2, - (1 << (SHORTBITS - 1)),
window_internal_width (w) - 1,
XINT (w->hscroll),
- pos_tab_offset (w, tlbufpos));
+ pos_tab_offset (w, tlbufpos), w);
if (pos.vpos < 1)
{
FRAME_CURSOR_X (selected_frame)
{
Lisp_Object tail, frame;
+#ifdef HAVE_X_WINDOWS
+ /* Since we're doing a thorough redisplay, we might as well
+ recompute all our display faces. */
+ clear_face_vector ();
+#endif
+
/* Recompute # windows showing selected buffer.
This will be incremented each time such a window is displayed. */
buffer_shared = 0;
{
FRAME_PTR f;
- if (XTYPE (XCONS (tail)->car) != Lisp_Frame)
+ if (!FRAMEP (XCONS (tail)->car))
continue;
f = XFRAME (XCONS (tail)->car);
{
pause |= update_frame (f, 0, 0);
if (!pause)
- mark_window_display_accurate (f->root_window, 1);
+ {
+ mark_window_display_accurate (f->root_window, 1);
+ if (frame_up_to_date_hook != 0)
+ (*frame_up_to_date_hook) (f);
+ }
}
}
}
above call to update_frame would not have caught it. Catch
it here. */
{
- FRAME_PTR mini_frame =
- XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
+ FRAME_PTR mini_frame
+ = XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
if (mini_frame != selected_frame)
pause |= update_frame (mini_frame, 0, 0);
{
w->update_mode_line = Qnil;
XFASTINT (w->last_modified) = BUF_MODIFF (b);
- w->window_end_valid = Qt;
+ w->window_end_valid = w->buffer;
last_arrow_position = Voverlay_arrow_position;
last_arrow_string = Voverlay_arrow_string;
+ if (do_verify_charstarts)
+ verify_charstarts (w);
+ if (frame_up_to_date_hook != 0)
+ (*frame_up_to_date_hook) (selected_frame);
}
update_mode_lines = 0;
windows_or_buffers_changed = 0;
/* Change frame size now if a change is pending. */
do_pending_window_change ();
+
+ /* If we just did a pending size change, redisplay again
+ for the new size. */
+ if (windows_or_buffers_changed && !pause)
+ redisplay ();
}
/* Redisplay, but leave alone any recent echo area message
for (;!NILP (window); window = w->next)
{
- if (XTYPE (window) != Lisp_Window) abort ();
+ if (!WINDOWP (window)) abort ();
w = XWINDOW (window);
if (!NILP (w->buffer))
- XFASTINT (w->last_modified)
- = !flag ? 0
- : XBUFFER (w->buffer) == current_buffer
- ? MODIFF : BUF_MODIFF (XBUFFER (w->buffer));
- w->window_end_valid = Qt;
+ {
+ XFASTINT (w->last_modified)
+ = !flag ? 0
+ : XBUFFER (w->buffer) == current_buffer
+ ? MODIFF : BUF_MODIFF (XBUFFER (w->buffer));
+
+ /* Record if we are showing a region, so can make sure to
+ update it fully at next redisplay. */
+ w->region_showing = (!NILP (Vtransient_mark_mode)
+ && !NILP (XBUFFER (w->buffer)->mark_active)
+ ? Fmarker_position (XBUFFER (w->buffer)->mark)
+ : Qnil);
+ }
+
+ w->window_end_valid = w->buffer;
w->update_mode_line = Qnil;
if (!NILP (w->vchild))
}
}
\f
+/* Update the menu bar item list for frame F.
+ This has to be done before we start to fill in any display lines,
+ because it can call eval. */
+
+static void
+update_menu_bar (f)
+ FRAME_PTR f;
+{
+ struct buffer *old = current_buffer;
+ Lisp_Object window;
+ register struct window *w;
+ window = FRAME_SELECTED_WINDOW (f);
+ w = XWINDOW (window);
+
+ if (update_mode_lines)
+ w->update_mode_line = Qt;
+
+ if (
+#ifdef USE_X_TOOLKIT
+ FRAME_EXTERNAL_MENU_BAR (f)
+#else
+ FRAME_MENU_BAR_LINES (f) > 0
+#endif
+ )
+ {
+ /* If the user has switched buffers or windows, we need to
+ recompute to reflect the new bindings. But we'll
+ recompute when update_mode_lines is set too; that means
+ that people can use force-mode-line-update to request
+ that the menu bar be recomputed. The adverse effect on
+ the rest of the redisplay algorithm is about the same as
+ windows_or_buffers_changed anyway. */
+ if (windows_or_buffers_changed
+ || !NILP (w->update_mode_line)
+ || (XFASTINT (w->last_modified) < MODIFF
+ && (XFASTINT (w->last_modified)
+ <= XBUFFER (w->buffer)->save_modified)))
+ {
+ struct buffer *prev = current_buffer;
+ call1 (Vrun_hooks, Qmenu_bar_update_hook);
+ current_buffer = XBUFFER (w->buffer);
+ FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
+ current_buffer = prev;
+#ifdef USE_X_TOOLKIT
+ set_frame_menubar (f, 0);
+#endif /* USE_X_TOOLKIT */
+ }
+ }
+}
+\f
int do_id = 1;
+/* Redisplay WINDOW and its subwindows and siblings. */
+
static void
redisplay_windows (window)
Lisp_Object window;
redisplay_window (window, 0);
}
+/* Redisplay window WINDOW and its subwindows. */
+
static void
redisplay_window (window, just_this_one)
Lisp_Object window;
register struct window *w = XWINDOW (window);
FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
int height;
- register int lpoint = point;
+ register int lpoint = PT;
struct buffer *old = current_buffer;
register int width = window_internal_width (w) - 1;
register int startp;
register int hscroll = XINT (w->hscroll);
struct position pos;
- int opoint = point;
+ int opoint = PT;
int tem;
int window_needs_modeline;
for (i = 0; i < height; i++)
{
get_display_line (f, vpos + i, 0);
- display_string (w, vpos + i, "", 0, 0, 0, width);
+ display_string (w, vpos + i, "", 0, 0, 0, 1, 0, width);
}
goto finish_scroll_bars;
/* Otherwise set up data on this window; select its buffer and point value */
current_buffer = XBUFFER (w->buffer);
- opoint = point;
+ opoint = PT;
/* Count number of windows showing the selected buffer. */
if (!EQ (window, selected_window))
{
- SET_PT (marker_position (w->pointm));
- if (point < BEGV)
+ int new_pt = marker_position (w->pointm);
+ if (new_pt < BEGV)
{
- SET_PT (BEGV);
- Fset_marker (w->pointm, make_number (point), Qnil);
+ new_pt = BEGV;
+ Fset_marker (w->pointm, make_number (new_pt), Qnil);
}
- else if (point > (ZV - 1))
+ else if (new_pt > (ZV - 1))
{
- SET_PT (ZV);
- Fset_marker (w->pointm, make_number (point), Qnil);
+ new_pt = ZV;
+ Fset_marker (w->pointm, make_number (new_pt), Qnil);
}
+ /* We don't use SET_PT so that the point-motion hooks don't run. */
+ BUF_PT (current_buffer) = new_pt;
}
/* If window-start is screwed up, choose a new one. */
startp = marker_position (w->start);
/* Handle case where place to start displaying has been specified,
- unless the specified location is outside the visible range. */
+ unless the specified location is outside the accessible range. */
if (!NILP (w->force_start))
{
+ /* Forget any recorded base line for line number display. */
+ w->base_line_number = Qnil;
w->update_mode_line = Qt;
w->force_start = Qnil;
XFASTINT (w->last_modified) = 0;
try_window (window, startp);
if (cursor_vpos < 0)
{
+ /* ??? What should happen here if highlighting a region? */
/* If point does not appear, move point so it does appear */
pos = *compute_motion (startp, 0,
((EQ (window, minibuf_window) && startp == 1)
(hscroll ? 1 - hscroll : 0),
ZV, height / 2,
- (1 << (SHORTBITS - 1)),
- width, hscroll, pos_tab_offset (w, startp));
- SET_PT (pos.bufpos);
- if (w != XWINDOW (FRAME_SELECTED_WINDOW (f)))
- Fset_marker (w->pointm, make_number (point), Qnil);
+ width, hscroll, pos_tab_offset (w, startp), w);
+ BUF_PT (current_buffer) = pos.bufpos;
+ if (w != XWINDOW (selected_window))
+ Fset_marker (w->pointm, make_number (PT), Qnil);
else
{
- lpoint = point;
+ if (current_buffer == old)
+ lpoint = PT;
FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left);
FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
}
in redisplay handles the same cases. */
if (XFASTINT (w->last_modified) >= MODIFF
- && point >= startp && !clip_changed
+ && PT >= startp && !clip_changed
&& (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
+ /* Can't use this case if highlighting a region. */
+ && !(!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
+ && NILP (w->region_showing)
+ /* If end pos is out of date, scroll bar and percentage will be wrong */
+ && INTEGERP (w->window_end_vpos)
+ && XFASTINT (w->window_end_vpos) < XFASTINT (w->height)
&& !EQ (window, minibuf_window))
{
pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
- point, height + 1, 10000, width, hscroll,
- pos_tab_offset (w, startp));
+ PT, height + 1, 10000, width, hscroll,
+ pos_tab_offset (w, startp), w);
if (pos.vpos < height)
{
/* If current starting point was originally the beginning of a line
but no longer is, find a new starting point. */
else if (!NILP (w->start_at_line_beg)
- && !(startp == BEGV
+ && !(startp <= BEGV
|| FETCH_CHAR (startp - 1) == '\n'))
{
goto recenter;
}
else if (just_this_one && !MINI_WINDOW_P (w)
- && point >= startp
+ && PT >= startp
&& XFASTINT (w->last_modified)
+ /* or else vmotion on first line won't work. */
+ && ! NILP (w->start_at_line_beg)
&& ! EQ (w->window_end_valid, Qnil)
&& do_id && !clip_changed
&& !blank_end_of_window
&& XFASTINT (w->width) == FRAME_WIDTH (f)
+ /* Can't use this case if highlighting a region. */
+ && !(!NILP (Vtransient_mark_mode)
+ && !NILP (current_buffer->mark_active))
+ && NILP (w->region_showing)
&& EQ (last_arrow_position, Voverlay_arrow_position)
&& EQ (last_arrow_string, Voverlay_arrow_string)
&& (tem = try_window_id (FRAME_SELECTED_WINDOW (f)))
/* If point has not moved off frame, accept the results */
try_window (window, startp);
if (cursor_vpos >= 0)
- goto done;
+ {
+ if (!just_this_one || clip_changed || beg_unchanged < startp)
+ /* Forget any recorded base line for line number display. */
+ w->base_line_number = Qnil;
+ goto done;
+ }
else
cancel_my_columns (w);
}
if (scroll_step && !clip_changed)
{
- if (point > startp)
+ if (PT > startp)
{
pos = *vmotion (Z - XFASTINT (w->window_end_pos),
scroll_step, width, hscroll, window);
goto scroll_fail;
}
- pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step,
+ pos = *vmotion (startp, PT < startp ? - scroll_step : scroll_step,
width, hscroll, window);
- if (point >= pos.bufpos)
+ if (PT >= pos.bufpos)
{
try_window (window, pos.bufpos);
if (cursor_vpos >= 0)
- goto done;
+ {
+ if (!just_this_one || clip_changed || beg_unchanged < startp)
+ /* Forget any recorded base line for line number display. */
+ w->base_line_number = Qnil;
+ goto done;
+ }
else
cancel_my_columns (w);
}
/* Finally, just choose place to start which centers point */
recenter:
- pos = *vmotion (point, - height / 2, width, hscroll, window);
+ /* Forget any previously recorded base line for line number display. */
+ w->base_line_number = Qnil;
+
+ pos = *vmotion (PT, - (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;
+ 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 ((!NILP (w->update_mode_line)
- || (!just_this_one && width < FRAME_WIDTH (f) - 1))
+ /* If window not full width, must redo its mode line
+ if the window to its side is being redone */
+ || (!just_this_one && width < FRAME_WIDTH (f) - 1)
+ || INTEGERP (w->base_line_pos))
&& height != XFASTINT (w->height))
display_mode_line (w);
+ if (! line_number_displayed
+ && ! BUFFERP (w->base_line_pos))
+ {
+ w->base_line_pos = Qnil;
+ w->base_line_number = Qnil;
+ }
/* When we reach a frame's selected window, redo the frame's menu bar. */
if (!NILP (w->update_mode_line)
+#ifdef USE_X_TOOLKIT
+ && FRAME_EXTERNAL_MENU_BAR (f)
+#else
&& FRAME_MENU_BAR_LINES (f) > 0
+#endif
&& EQ (FRAME_SELECTED_WINDOW (f), window))
display_menu_bar (w);
int start, end, whole;
/* Calculate the start and end positions for the current window.
+ At some point, it would be nice to choose between scrollbars
+ which reflect the whole buffer size, with special markers
+ indicating narrowing, and scrollbars which reflect only the
+ visible region.
+
Note that minibuffers sometimes aren't displaying any text. */
if (! MINI_WINDOW_P (w)
|| (w == XWINDOW (minibuf_window) && ! echo_area_glyphs))
{
- start = startp;
+ whole = ZV - BEGV;
+ start = startp - BEGV;
/* I don't think this is guaranteed to be right. For the
moment, we'll pretend it is. */
- end = Z - XINT (w->window_end_pos);
- whole = Z - BEG;
+ end = (Z - XINT (w->window_end_pos)) - BEGV;
+
+ if (end < start) end = start;
+ if (whole < (end - start)) whole = end - start;
}
else
start = end = whole = 0;
/* Indicate what this scroll bar ought to be displaying now. */
- (*set_vertical_scroll_bar_hook) (w, end - start, whole, start - 1);
+ (*set_vertical_scroll_bar_hook) (w, end - start, whole, start);
/* Note that we actually used the scroll bar attached to this window,
so it shouldn't be deleted at the end of redisplay. */
(*redeem_scroll_bar_hook) (w);
}
- SET_PT (opoint);
+ BUF_PT (current_buffer) = opoint;
current_buffer = old;
- SET_PT (lpoint);
+ BUF_PT (current_buffer) = lpoint;
}
\f
/* Do full redisplay on one window, starting at position `pos'. */
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');
+ = vpos - (val.vpos && (FETCH_CHAR (val.bufpos - 1) != '\n'
+#ifdef USE_TEXT_PROPERTIES
+ || ! NILP (Fget_char_property (val.bufpos-1,
+ Qinvisible,
+ window))
+#endif
+ ));
pos = val.bufpos;
}
register int i, tem;
int last_text_vpos = 0;
int stop_vpos;
+ int selective = (INTEGERP (current_buffer->selective_display)
+ ? XINT (current_buffer->selective_display)
+ : !NILP (current_buffer->selective_display) ? -1 : 0);
struct position val, bp, ep, xp, pp;
int scroll_amount = 0;
if (Z - GPT < end_unchanged)
end_unchanged = Z - GPT;
- if (beg_unchanged + 1 < start)
+ if (beg_unchanged + BEG < 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, height + 1, 0, width, hscroll,
- pos_tab_offset (w, start));
+ min (ZV, beg_unchanged + BEG), height + 1, 0,
+ width, hscroll, pos_tab_offset (w, start), w);
if (bp.vpos >= height)
{
- if (point < bp.bufpos && !bp.contin)
+ if (PT < bp.bufpos && !bp.contin)
{
/* All changes are below the frame, and point is on the frame.
We don't need to change the frame at all.
any change in buffer size. */
bp = *compute_motion (start, 0, lmargin,
Z, height, 0,
- width, hscroll, pos_tab_offset (w, start));
+ width, hscroll, pos_tab_offset (w, start), w);
XFASTINT (w->window_end_vpos) = height;
XFASTINT (w->window_end_pos) = Z - bp.bufpos;
return 1;
if ((bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0)
||
/* Likewise if we have to worry about selective display. */
- (XTYPE (current_buffer->selective_display) == Lisp_Int
- && XINT (current_buffer->selective_display) > 0
- && bp.bufpos - 1 == beg_unchanged && vpos > 0))
+ (selective > 0 && bp.bufpos - 1 == beg_unchanged && vpos > 0))
{
bp = *vmotion (bp.bufpos, -1, width, hscroll, window);
--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)))
+ if (selective > 0)
+ while (tem < ZV - 1 && (indented_beyond_p (tem, selective)))
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));
+ width, hscroll, pos_tab_offset (w, bp.bufpos), w);
/* If changes reach past the text available on the frame,
just display rest of frame. */
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);
+ 10000, 0, width, hscroll, epto, w);
scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
/* Is everything on frame below the changes whitespace?
XFASTINT (w->window_end_vpos) += scroll_amount;
/* Before doing any scrolling, verify that point will be on frame. */
- if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height))
+ if (PT > ep.bufpos && !(PT <= xp.bufpos && xp.bufpos < height))
{
- if (point <= xp.bufpos)
+ if (PT <= xp.bufpos)
{
pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
- point, height, - (1 << (SHORTBITS - 1)),
- width, hscroll, epto);
+ PT, height, - (1 << (SHORTBITS - 1)),
+ width, hscroll, epto, w);
}
else
{
pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
- point, height, - (1 << (SHORTBITS - 1)),
- width, hscroll, pos_tab_offset (w, xp.bufpos));
+ PT, height, - (1 << (SHORTBITS - 1)),
+ width, hscroll,
+ pos_tab_offset (w, xp.bufpos), w);
}
- if (pp.bufpos < point || pp.vpos == height)
+ if (pp.bufpos < PT || pp.vpos == height)
return 0;
cursor_vpos = pp.vpos + top;
cursor_hpos = pp.hpos + XFASTINT (w->left);
blank_end_of_window = 1;
}
else if (!scroll_amount)
- {}
+ {
+ /* Even if we don't need to scroll, we must adjust the
+ charstarts of subsequent lines (that we won't redisplay)
+ according to the amount of text inserted or deleted. */
+ int oldpos = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0];
+ int adjust = ep.bufpos - oldpos;
+ adjust_window_charstarts (w, ep.vpos + top - 1, adjust);
+ }
else if (bp.bufpos == Z - end_unchanged)
{
/* If reprinting everything is nearly as fast as scrolling,
following line from being overwritten by scrolling
and therefore having to be redrawn. */
tem = scroll_frame_lines (f, bp.vpos + top - scroll_amount,
- top + height - max (0, scroll_amount),
- scroll_amount);
- if (!tem) stop_vpos = height;
+ top + height - max (0, scroll_amount),
+ scroll_amount, bp.bufpos);
+ if (!tem)
+ stop_vpos = height;
+ else
+ {
+ /* scroll_frame_lines did not properly adjust subsequent
+ lines' charstarts in the case where the text of the
+ screen line at bp.vpos has changed.
+ (This can happen in a deletion that ends in mid-line.)
+ To adjust properly, we need to make things constent at
+ the position ep.
+ So do a second adjust to make that happen.
+ Note that stop_vpos >= ep.vpos, so it is sufficient
+ to update the charstarts for lines at ep.vpos and below. */
+ int oldstart
+ = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0];
+ adjust_window_charstarts (w, ep.vpos + top - 1,
+ ep.bufpos - oldstart);
+ }
}
else if (scroll_amount)
{
return -2;
tem = scroll_frame_lines (f, ep.vpos + top - scroll_amount,
top + height - max (0, scroll_amount),
- scroll_amount);
+ scroll_amount, ep.bufpos);
if (!tem) stop_vpos = height;
}
}
/* 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)
+ && xp.bufpos == PT)
cursor_vpos = -1;
}
/* 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));
+ val = *compute_motion (start, 0, lmargin, PT, 10000, 10000,
+ width, hscroll, pos_tab_offset (w, start), w);
/* Admit failure if point is off frame now */
if (val.vpos >= height)
{
{
val = *compute_motion (start, 0, lmargin, ZV,
height, - (1 << (SHORTBITS - 1)),
- width, hscroll, pos_tab_offset (w, start));
+ width, hscroll, pos_tab_offset (w, start), w);
if (val.vpos != XFASTINT (w->window_end_vpos))
abort ();
if (XFASTINT (w->window_end_pos)
return 1;
}
\f
-/* Copy glyphs from the vector FROM to the rope T.
- But don't actually copy the parts that would come in before S.
- Value is T, advanced past the copied data. */
+/* Mark a section of BUF as modified, but only for the sake of redisplay.
+ This is useful for recording changes to overlays.
-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 vector. */
+ We increment the buffer's modification timestamp and set the
+ redisplay caches (windows_or_buffers_changed, beg_unchanged, etc)
+ as if the region of text between START and END had been modified;
+ the redisplay code will check this against the windows' timestamps,
+ and redraw the appropriate area of the buffer.
+
+ However, if the buffer is unmodified, we bump the last-save
+ timestamp as well, so that incrementing the timestamp doesn't fool
+ Emacs into thinking that the buffer's text has been modified.
+
+ Tweaking the timestamps shouldn't hurt the first-modification
+ timestamps recorded in the undo records; those values aren't
+ written until just before a real text modification is made, so they
+ will never catch the timestamp value just before this function gets
+ called. */
+
+void
+redisplay_region (buf, start, end)
+ struct buffer *buf;
+ int start, end;
{
- register int n = XVECTOR (from)->size;
- register Lisp_Object *f = XVECTOR (from)->contents;
+ if (start == end)
+ return;
- while (n--)
+ if (start > end)
{
- if (t >= s) *t = *f;
- ++t;
- ++f;
+ int temp = start;
+ start = end; end = temp;
}
- return t;
+
+ /* If this is a buffer not in the selected window,
+ we must do other windows. */
+ if (buf != XBUFFER (XWINDOW (selected_window)->buffer))
+ windows_or_buffers_changed = 1;
+ /* If it's not current, we can't use beg_unchanged, end_unchanged for it. */
+ else if (buf != current_buffer)
+ windows_or_buffers_changed = 1;
+ /* If multiple windows show this buffer, we must do other windows. */
+ else if (buffer_shared > 1)
+ windows_or_buffers_changed = 1;
+ else
+ {
+ if (unchanged_modified == MODIFF)
+ {
+ beg_unchanged = start - BEG;
+ end_unchanged = Z - end;
+ }
+ else
+ {
+ if (Z - end < end_unchanged)
+ end_unchanged = Z - end;
+ if (start - BEG < beg_unchanged)
+ beg_unchanged = start - BEG;
+ }
+ }
+
+ /* Increment the buffer's time stamp, but also increment the save
+ and autosave timestamps, so as not to screw up that timekeeping. */
+ if (BUF_MODIFF (buf) == buf->save_modified)
+ buf->save_modified++;
+ if (BUF_MODIFF (buf) == buf->auto_save_modified)
+ buf->auto_save_modified++;
+
+ BUF_MODIFF (buf) ++;
}
-/* Similar but copy at most LEN glyphs. */
+\f
+/* Copy LEN glyphs starting address FROM to the rope TO.
+ But don't actually copy the parts that would come in before S.
+ Value is TO, advanced past the copied data.
+ F is the frame we are displaying in. */
-GLYPH *
-copy_part_of_rope (t, s, from, len)
- register GLYPH *t; /* Copy to here. */
+static GLYPH *
+copy_part_of_rope (f, to, s, from, len, face)
+ FRAME_PTR f;
+ register GLYPH *to; /* Copy to here. */
register GLYPH *s; /* Starting point. */
- Lisp_Object from; /* Data to copy; known to be a vector. */
+ Lisp_Object *from; /* Data to copy. */
int len;
+ int face; /* Face to apply to glyphs which don't specify one. */
{
- register int n = XVECTOR (from)->size;
- register Lisp_Object *f = XVECTOR (from)->contents;
+ int n = len;
+ register Lisp_Object *fp = from;
+ /* These cache the results of the last call to compute_glyph_face. */
+ int last_code = -1;
+ int last_merged = 0;
+
+#ifdef HAVE_X_WINDOWS
+ if (! FRAME_TERMCAP_P (f))
+ while (n--)
+ {
+ int glyph = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
+ int facecode;
+
+ if (FAST_GLYPH_FACE (glyph) == 0)
+ /* If GLYPH has no face code, use FACE. */
+ facecode = face;
+ else if (FAST_GLYPH_FACE (glyph) == last_code)
+ /* If it's same as previous glyph, use same result. */
+ facecode = last_merged;
+ else
+ {
+ /* Merge this glyph's face and remember the result. */
+ last_code = FAST_GLYPH_FACE (glyph);
+ last_merged = facecode = compute_glyph_face (f, last_code, face);
+ }
+
+ if (to >= s)
+ *to = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), facecode);
+ ++to;
+ ++fp;
+ }
+ else
+#endif
+ while (n--)
+ {
+ if (to >= s) *to = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
+ ++to;
+ ++fp;
+ }
+ return to;
+}
- if (n > len)
- n = len;
+/* Correct a glyph by replacing its specified user-level face code
+ with a displayable computed face code. */
- while (n--)
+static GLYPH
+fix_glyph (f, glyph, cface)
+ FRAME_PTR f;
+ GLYPH glyph;
+ int cface;
+{
+#ifdef HAVE_X_WINDOWS
+ if (! FRAME_TERMCAP_P (f))
{
- if (t >= s) *t = *f;
- ++t;
- ++f;
+ if (FAST_GLYPH_FACE (glyph) != 0)
+ cface = compute_glyph_face (f, FAST_GLYPH_FACE (glyph), cface);
+ glyph = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), cface);
}
- return t;
+#endif
+ return glyph;
}
\f
/* Display one line of window w, starting at position START in W's buffer.
register int pause;
register unsigned char *p;
GLYPH *endp;
- register GLYPH *startp;
- register GLYPH *p1prev;
+ register GLYPH *leftmargin;
+ register GLYPH *p1prev = 0;
+ register GLYPH *p1start;
+ int *charstart;
FRAME_PTR f = XFRAME (w->frame);
int tab_width = XINT (current_buffer->tab_width);
int ctl_arrow = !NILP (current_buffer->ctl_arrow);
int lastpos;
int invis;
int hscroll = XINT (w->hscroll);
- int truncate = hscroll
- || (truncate_partial_width_windows
- && XFASTINT (w->width) < FRAME_WIDTH (f))
- || !NILP (current_buffer->truncate_lines);
- int selective
- = XTYPE (current_buffer->selective_display) == Lisp_Int
- ? XINT (current_buffer->selective_display)
- : !NILP (current_buffer->selective_display) ? -1 : 0;
-#ifndef old
- int selective_e = selective && !NILP (current_buffer->selective_display_ellipses);
-#endif
+ int truncate = (hscroll
+ || (truncate_partial_width_windows
+ && XFASTINT (w->width) < FRAME_WIDTH (f))
+ || !NILP (current_buffer->truncate_lines));
+
+ /* 1 if we should highlight the region. */
+ int highlight_region
+ = !NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active);
+ int region_beg, region_end;
+
+ int selective = (INTEGERP (current_buffer->selective_display)
+ ? XINT (current_buffer->selective_display)
+ : !NILP (current_buffer->selective_display) ? -1 : 0);
register struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
register struct Lisp_Vector *dp = window_display_table (w);
+
+ Lisp_Object default_invis_vector[3];
+ /* Nonzero means display something where there are invisible lines.
+ The precise value is the number of glyphs to display. */
int selective_rlen
- = (selective && dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector
- ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 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)));
+ = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
+ ? XVECTOR (DISP_INVIS_VECTOR (dp))->size
+ : selective && !NILP (current_buffer->selective_display_ellipses)
+ ? 3 : 0);
+ /* This is the sequence of Lisp objects to display
+ when there are invisible lines. */
+ Lisp_Object *invis_vector_contents
+ = (dp && VECTORP (DISP_INVIS_VECTOR (dp))
+ ? XVECTOR (DISP_INVIS_VECTOR (dp))->contents
+ : default_invis_vector);
+
+ GLYPH truncator = (dp == 0 || !INTEGERP (DISP_TRUNC_GLYPH (dp))
+ ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
+ GLYPH continuer = (dp == 0 || !INTEGERP (DISP_CONTINUE_GLYPH (dp))
+ ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
+
+ /* The next buffer location at which the face should change, due
+ to overlays or text property changes. */
+ int next_face_change;
+
+#ifdef USE_TEXT_PROPERTIES
+ /* The next location where the `invisible' property changes */
+ int next_invisible;
+#endif
+
+ /* The face we're currently using. */
+ int current_face = 0;
+ int i;
+
+ XFASTINT (default_invis_vector[2]) = '.';
+ default_invis_vector[0] = default_invis_vector[1] = default_invis_vector[2];
hpos += XFASTINT (w->left);
get_display_line (f, vpos, XFASTINT (w->left));
- if (tab_width <= 0 || tab_width > 20) tab_width = 8;
+ if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
+
+ /* Show where to highlight the region. */
+ if (highlight_region && XMARKER (current_buffer->mark)->buffer != 0
+ /* Maybe highlight only in selected window. */
+ && (highlight_nonselected_windows
+ || w == XWINDOW (selected_window)))
+ {
+ region_beg = marker_position (current_buffer->mark);
+ if (PT < region_beg)
+ {
+ region_end = region_beg;
+ region_beg = PT;
+ }
+ else
+ region_end = PT;
+ w->region_showing = Qt;
+ }
+ else
+ region_beg = region_end = -1;
if (MINI_WINDOW_P (w) && start == 1
&& vpos == XFASTINT (w->top))
{
- if (minibuf_prompt)
- hpos = display_string (w, vpos, minibuf_prompt, hpos,
+ if (! NILP (minibuf_prompt))
+ {
+ minibuf_prompt_width
+ = (display_string (w, vpos, XSTRING (minibuf_prompt)->data,
+ XSTRING (minibuf_prompt)->size, hpos,
(!truncate ? continuer : truncator),
- -1, -1);
- minibuf_prompt_width = hpos;
+ 1, -1, -1)
+ - hpos);
+ hpos += minibuf_prompt_width;
+ }
+ else
+ minibuf_prompt_width = 0;
}
desired_glyphs->bufp[vpos] = pos;
p1 = desired_glyphs->glyphs[vpos] + hpos;
+ p1start = p1;
+ charstart = desired_glyphs->charstarts[vpos] + hpos;
+ /* In case we don't ever write anything into it... */
+ desired_glyphs->charstarts[vpos][XFASTINT (w->left)] = -1;
end = ZV;
- startp = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
- endp = startp + width;
+ leftmargin = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
+ endp = leftmargin + width;
+
+ /* Arrange the overlays nicely for our purposes. Usually, we call
+ display_text_line on only one line at a time, in which case this
+ can't really hurt too much, or we call it on lines which appear
+ one after another in the buffer, in which case all calls to
+ recenter_overlay_lists but the first will be pretty cheap. */
+ recenter_overlay_lists (current_buffer, pos);
/* Loop generating characters.
Stop at end of buffer, before newline,
- or if reach or pass continuation column. */
-
+ if reach or pass continuation column,
+ or at face change. */
pause = pos;
- while (p1 < endp)
+ next_face_change = pos;
+#ifdef USE_TEXT_PROPERTIES
+ next_invisible = pos;
+#endif
+ while (1)
{
+ /* Record which glyph starts a character,
+ and the character position of that character. */
+ if (p1 >= leftmargin)
+ charstart[p1 - p1start] = pos;
+
+ if (p1 >= endp)
+ break;
+
p1prev = p1;
- if (pos == pause)
+ if (pos >= pause)
{
- if (pos == end)
+ /* Did we hit the end of the visible region of the buffer?
+ Stop here. */
+ if (pos >= end)
break;
- if (pos == point && cursor_vpos < 0)
+
+ /* Did we reach point? Record the cursor location. */
+ if (pos == PT && cursor_vpos < 0)
{
cursor_vpos = vpos;
- cursor_hpos = p1 - startp;
+ cursor_hpos = p1 - leftmargin;
+ }
+
+#ifdef USE_TEXT_PROPERTIES
+ /* if the `invisible' property is set to t, we can skip to
+ the next property change */
+ while (pos == next_invisible && pos < end)
+ {
+ Lisp_Object position, limit, endpos, prop, ww;
+ XFASTINT (position) = pos;
+ XSET (ww, Lisp_Window, w);
+ prop = Fget_char_property (position, Qinvisible, ww);
+ /* This is just an estimate to give reasonable
+ performance; nothing should go wrong if it is too small. */
+ limit = Fnext_overlay_change (position);
+ if (XFASTINT (limit) > pos + 50)
+ XFASTINT (limit) = pos + 50;
+ endpos = Fnext_single_property_change (position, Qinvisible,
+ Fcurrent_buffer (), limit);
+ if (INTEGERP (endpos))
+ next_invisible = XINT (endpos);
+ else
+ next_invisible = end;
+ if (! NILP (prop))
+ {
+ if (pos < PT && next_invisible >= PT)
+ {
+ cursor_vpos = vpos;
+ cursor_hpos = p1 - leftmargin;
+ }
+ pos = next_invisible;
+ }
}
+ if (pos >= end)
+ break;
+#endif
+
+#ifdef HAVE_X_WINDOWS
+ /* Did we hit a face change? Figure out what face we should
+ use now. We also hit this the first time through the
+ loop, to see what face we should start with. */
+ if (pos >= next_face_change && FRAME_X_P (f))
+ current_face = compute_char_face (f, w, pos,
+ region_beg, region_end,
+ &next_face_change, pos + 50, 0);
+#endif
pause = end;
- if (pos < point && point < pause)
- pause = point;
+
+#ifdef USE_TEXT_PROPERTIES
+ if (pos < next_invisible && next_invisible < pause)
+ pause = next_invisible;
+#endif
+ if (pos < next_face_change && next_face_change < pause)
+ pause = next_face_change;
+
+ /* Wouldn't you hate to read the next line to someone over
+ the phone? */
+ if (pos < PT && PT < pause)
+ pause = PT;
if (pos < GPT && GPT < pause)
pause = GPT;
}
c = *p++;
if (c >= 040 && c < 0177
- && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
+ && (dp == 0 || !VECTORP (DISP_CHAR_VECTOR (dp, c))))
{
- if (p1 >= startp)
- *p1 = c;
+ if (p1 >= leftmargin)
+ *p1 = MAKE_GLYPH (f, c, current_face);
p1++;
}
else if (c == '\n')
{
invis = 0;
- while (pos < end
+ while (pos + 1 < end
&& selective > 0
- && position_indentation (pos + 1) >= selective)
+ && indented_beyond_p (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)
+ if (invis && selective_rlen > 0 && p1 >= leftmargin)
{
p1 += selective_rlen;
- if (p1 - startp > width)
+ if (p1 - leftmargin > width)
p1 = endp;
- copy_part_of_rope (p1prev, p1prev,
- XVECTOR (DISP_INVIS_VECTOR (dp))->contents,
- (p1 - p1prev));
+ copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
+ (p1 - p1prev), current_face);
+ }
+#ifdef HAVE_X_WINDOWS
+ /* Draw the face of the newline character as extending all the
+ way to the end of the frame line. */
+ if (current_face)
+ {
+ if (p1 < leftmargin)
+ p1 = leftmargin;
+ while (p1 < endp)
+ *p1++ = FAST_MAKE_GLYPH (' ', current_face);
}
+#endif
break;
}
else if (c == '\t')
{
do
{
- if (p1 >= startp && p1 < endp)
- *p1 = SPACEGLYPH;
+ if (p1 >= leftmargin && p1 < endp)
+ *p1 = MAKE_GLYPH (f, ' ', current_face);
p1++;
}
- while ((p1 - startp + taboffset + hscroll - (hscroll > 0))
+ while ((p1 - leftmargin + taboffset + hscroll - (hscroll > 0))
% tab_width);
}
else if (c == Ctl ('M') && selective == -1)
if (selective_rlen > 0)
{
p1 += selective_rlen;
- if (p1 - startp > width)
+ if (p1 - leftmargin > width)
p1 = endp;
- copy_part_of_rope (p1prev, p1prev,
- XVECTOR(DISP_INVIS_VECTOR (dp))->contents,
- (p1 - p1prev));
+ copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
+ (p1 - p1prev), current_face);
}
+#ifdef HAVE_X_WINDOWS
+ /* Draw the face of the newline character as extending all the
+ way to the end of the frame line. */
+ if (current_face)
+ {
+ if (p1 < leftmargin)
+ p1 = leftmargin;
+ while (p1 < endp)
+ *p1++ = FAST_MAKE_GLYPH (' ', current_face);
+ }
+#endif
break;
}
- else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
+ else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
{
- p1 = copy_rope (p1, startp, DISP_CHAR_VECTOR (dp, c));
+ p1 = copy_part_of_rope (f, p1, leftmargin,
+ XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
+ XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
+ current_face);
}
else if (c < 0200 && ctl_arrow)
{
- if (p1 >= startp)
- *p1 = (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
- ? XINT (DISP_CTRL_GLYPH (dp)) : '^');
+ if (p1 >= leftmargin)
+ *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
+ ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
+ current_face);
p1++;
- if (p1 >= startp && p1 < endp)
- *p1 = c ^ 0100;
+ if (p1 >= leftmargin && p1 < endp)
+ *p1 = MAKE_GLYPH (f, c ^ 0100, current_face);
p1++;
}
else
{
- if (p1 >= startp)
- *p1 = (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
- ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\');
+ if (p1 >= leftmargin)
+ *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
+ ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
+ current_face);
p1++;
- if (p1 >= startp && p1 < endp)
- *p1 = (c >> 6) + '0';
+ if (p1 >= leftmargin && p1 < endp)
+ *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face);
p1++;
- if (p1 >= startp && p1 < endp)
- *p1 = (7 & (c >> 3)) + '0';
+ if (p1 >= leftmargin && p1 < endp)
+ *p1 = MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face);
p1++;
- if (p1 >= startp && p1 < endp)
- *p1 = (7 & c) + '0';
+ if (p1 >= leftmargin && p1 < endp)
+ *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face);
p1++;
}
+
+ /* Do nothing here for a char that's entirely off the left edge. */
+ if (p1 >= leftmargin)
+ {
+ /* For all the glyphs occupied by this character, except for the
+ first, store -1 in charstarts. */
+ if (p1 != p1prev)
+ {
+ int *p2x = &charstart[p1prev - p1start];
+ int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
+
+ /* The window's left column should always
+ contain a character position.
+ And don't clobber anything to the left of that. */
+ if (p1prev < leftmargin)
+ {
+ p2x = charstart + (leftmargin - p1start);
+ *p2x = pos;
+ }
+
+ /* This loop skips over the char p2x initially points to. */
+ while (++p2x < p2)
+ *p2x = -1;
+ }
+ }
+
pos++;
}
lastpos = pos;
+ /* Store 0 in this charstart line for the positions where
+ there is no character. But do leave what was recorded
+ for the character that ended the line. */
+ /* Add 1 in the endtest to compensate for the fact that ENDP was
+ made from WIDTH, which is 1 less than the window's actual
+ internal width. */
+ i = p1 - p1start + 1;
+ if (p1 < leftmargin)
+ i += leftmargin - p1;
+ for (; i < endp - p1start + 1; i++)
+ charstart[i] = 0;
+
/* 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;
+ /* Don't back up if we never actually displayed any text.
+ This occurs when the minibuffer prompt takes up the whole line. */
+ if (p1prev)
+ {
+ /* Start the next line with that same character */
+ pos--;
+ /* but at 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;
}
if (pos < ZV)
{
if (FETCH_CHAR (pos) == '\n')
- /* If stopped due to a newline, start next line after it */
- pos++;
+ {
+ /* If stopped due to a newline, start next line after it */
+ pos++;
+ /* Check again for hidden lines, in case the newline occurred exactly
+ at the right margin. */
+ while (pos < ZV && selective > 0
+ && indented_beyond_p (pos, selective))
+ pos = find_next_newline (pos, 1);
+ }
else
/* Stopped due to right margin of window */
{
if (truncate)
{
- *p1++ = truncator;
+ *p1++ = fix_glyph (f, truncator, 0);
/* 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);
+ do
+ pos = find_next_newline (pos, 1);
+ while (pos < ZV && selective > 0
+ && indented_beyond_p (pos, selective));
val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
}
else
{
- *p1++ = continuer;
+ *p1++ = fix_glyph (f, continuer, 0);
val.vpos = 0;
lastpos--;
}
/* If point is at eol or in invisible text at eol,
record its frame location now. */
- if (start <= point && point <= lastpos && cursor_vpos < 0)
+ if (start <= PT && PT <= lastpos && cursor_vpos < 0)
{
cursor_vpos = vpos;
- cursor_hpos = p1 - startp;
+ cursor_hpos = p1 - leftmargin;
}
if (cursor_vpos == vpos)
/* If hscroll and line not empty, insert truncation-at-left marker */
if (hscroll && lastpos != start)
{
- *startp = truncator;
- if (p1 <= startp)
- p1 = startp + 1;
+ *leftmargin = fix_glyph (f, truncator, 0);
+ if (p1 <= leftmargin)
+ p1 = leftmargin + 1;
}
if (XFASTINT (w->width) + XFASTINT (w->left) != FRAME_WIDTH (f))
{
endp++;
- if (p1 < startp) p1 = startp;
+ if (p1 < leftmargin) p1 = leftmargin;
while (p1 < endp) *p1++ = SPACEGLYPH;
/* Don't draw vertical bars if we're using scroll bars. They're
them when the scroll bar windows are flickering around to be
reconfigured. */
*p1++ = (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
- ? ' ' : '|');
+ ? ' '
+ : (dp && INTEGERP (DISP_BORDER_GLYPH (dp))
+ ? DISP_BORDER_GLYPH (dp)
+ : '|'));
}
desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
p1 - desired_glyphs->glyphs[vpos]);
/* 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
+ if (MARKERP (Voverlay_arrow_position)
&& current_buffer == XMARKER (Voverlay_arrow_position)->buffer
&& start == marker_position (Voverlay_arrow_position)
- && XTYPE (Voverlay_arrow_string) == Lisp_String
+ && STRINGP (Voverlay_arrow_string)
&& ! overlay_arrow_seen)
{
unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
int i;
int len = XSTRING (Voverlay_arrow_string)->size;
+ int arrow_end;
if (len > width)
len = width;
- 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];
+#ifdef HAVE_X_WINDOWS
+ if (!NULL_INTERVAL_P (XSTRING (Voverlay_arrow_string)->intervals))
+ {
+ /* If the arrow string has text props, obey them when displaying. */
+ for (i = 0; i < len; i++)
+ {
+ int c = p[i];
+ Lisp_Object face, ilisp;
+ int newface;
+
+ XFASTINT (ilisp) = i;
+ face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string);
+ newface = compute_glyph_face_1 (f, face, 0);
+ leftmargin[i] = FAST_MAKE_GLYPH (c, newface);
+ }
+ }
+ else
+#endif /* HAVE_X_WINDOWS */
+ {
+ for (i = 0; i < len; i++)
+ leftmargin[i] = p[i];
+ }
+
+ /* Bug in SunOS 4.1.1 compiler requires this intermediate variable. */
+ arrow_end = (leftmargin - desired_glyphs->glyphs[vpos]) + len;
+ if (desired_glyphs->used[vpos] < arrow_end)
+ desired_glyphs->used[vpos] = arrow_end;
overlay_arrow_seen = 1;
}
register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
int maxendcol = FRAME_WIDTH (f);
int hpos = 0;
+ int i;
+#ifndef USE_X_TOOLKIT
if (FRAME_MENU_BAR_LINES (f) <= 0)
return;
get_display_line (f, vpos, 0);
- for (tail = FRAME_MENU_BAR_ITEMS (f); CONSP (tail); tail = XCONS (tail)->cdr)
+ items = FRAME_MENU_BAR_ITEMS (f);
+ for (i = 0; i < XVECTOR (items)->size; i += 3)
{
- Lisp_Object string;
+ Lisp_Object pos, string;
+ string = XVECTOR (items)->contents[i + 1];
+ if (NILP (string))
+ break;
- string = XCONS (XCONS (XCONS (tail)->car)->cdr)->car;
-
- /* Record in each item its hpos. */
- XFASTINT (XCONS (XCONS (XCONS (tail)->car)->cdr)->cdr) = hpos;
+ XFASTINT (XVECTOR (items)->contents[i + 2]) = hpos;
if (hpos < maxendcol)
hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
XSTRING (string)->data,
- hpos, 0, hpos, maxendcol);
+ XSTRING (string)->size,
+ hpos, 0, 0, hpos, maxendcol);
/* Put a gap of 3 spaces between items. */
if (hpos < maxendcol)
{
int hpos1 = hpos + 3;
- hpos = display_string (w, vpos, "", hpos, 0,
+ hpos = display_string (w, vpos, "", 0, hpos, 0, 0,
min (hpos1, maxendcol), maxendcol);
}
}
/* Fill out the line with spaces. */
if (maxendcol > hpos)
- hpos = display_string (w, vpos, "", hpos, 0, maxendcol, -1);
+ hpos = display_string (w, vpos, "", 0, hpos, 0, 0, maxendcol, maxendcol);
+
+ /* Clear the rest of the lines allocated to the menu bar. */
+ vpos++;
+ while (vpos < FRAME_MENU_BAR_LINES (f))
+ get_display_line (f, vpos++, 0);
+#endif /* not USE_X_TOOLKIT */
}
\f
/* Display the mode line for window w */
register int right = XFASTINT (w->width) + left;
register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
+ line_number_displayed = 0;
+
get_display_line (f, vpos, left);
display_mode_element (w, vpos, left, 0, right, right,
current_buffer->mode_line_format);
if (XFASTINT (w->width) == FRAME_WIDTH (f)
|| XFASTINT (XWINDOW (w->parent)->width) == FRAME_WIDTH (f))
FRAME_DESIRED_GLYPHS (f)->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 mess adversely with some window managers. -jla
-
- Wouldn't it be nice to use something like mode-line-format to
- describe frame titles? -JimB */
-
- /* Change the title of the frame to the name of the buffer displayed
- in the currently selected window. Don't do this for minibuffer frames,
- and don't do it when there's only one non-minibuffer frame. */
- if (FRAME_X_P (f)
- && ! FRAME_MINIBUF_ONLY_P (f)
- && w == XWINDOW (f->selected_window))
- x_implicitly_set_name (f, (EQ (Fnext_frame (WINDOW_FRAME (w), Qnil),
- WINDOW_FRAME (w))
- ? Qnil
- : XBUFFER (w->buffer)->name),
- Qnil);
+ else if (! FRAME_TERMCAP_P (f))
+ {
+ /* For a partial width window, explicitly set face of each glyph. */
+ int i;
+ GLYPH *ptr = FRAME_DESIRED_GLYPHS (f)->glyphs[vpos];
+ for (i = left; i < right; ++i)
+ ptr[i] = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (ptr[i]), 1);
+ }
#endif
}
if (this - 1 != last)
{
register int lim = --this - last + hpos;
- hpos = display_string (w, vpos, last, hpos, 0, hpos,
- min (lim, maxendcol));
+ if (frame_title_ptr)
+ hpos = store_frame_title (last, hpos, min (lim, maxendcol));
+ else
+ hpos = display_string (w, vpos, last, -1, hpos, 0, 1,
+ hpos, min (lim, maxendcol));
}
else /* c == '%' */
{
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);
+ {
+ char *spec = decode_mode_spec (w, c, maxendcol - hpos);
+ if (frame_title_ptr)
+ hpos = store_frame_title (spec, spec_width, maxendcol);
+ else
+ hpos = display_string (w, vpos, spec, -1,
+ hpos, 0, 1,
+ spec_width, maxendcol);
+ }
}
}
}
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);
+ if (STRINGP (tem))
+ {
+ if (frame_title_ptr)
+ hpos = store_frame_title (XSTRING (tem)->data,
+ minendcol, maxendcol);
+ else
+ hpos = display_string (w, vpos, XSTRING (tem)->data,
+ XSTRING (tem)->size,
+ hpos, 0, 1, minendcol, maxendcol);
+ }
/* Give up right away for nil or t. */
else if (!EQ (tem, elt))
{ elt = tem; goto tail_recurse; }
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)
+ if (SYMBOLP (car))
{
tem = Fboundp (car);
elt = XCONS (elt)->cdr;
- if (XTYPE (elt) != Lisp_Cons)
+ if (!CONSP (elt))
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. */
elt = XCONS (elt)->cdr;
if (NILP (elt))
break;
- else if (XTYPE (elt) != Lisp_Cons)
+ else if (!CONSP (elt))
goto invalid;
elt = XCONS (elt)->car;
goto tail_recurse;
}
- else if (XTYPE (car) == Lisp_Int)
+ else if (INTEGERP (car))
{
register int lim = XINT (car);
elt = XCONS (elt)->cdr;
}
goto tail_recurse;
}
- else if (XTYPE (car) == Lisp_String || XTYPE (car) == Lisp_Cons)
+ else if (STRINGP (car) || CONSP (car))
{
register int limit = 50;
/* LIMIT is to protect against circular lists. */
- while (XTYPE (elt) == Lisp_Cons && --limit > 0
+ while (CONSP (elt) && --limit > 0
&& hpos < maxendcol)
{
hpos = display_mode_element (w, vpos, hpos, depth,
default:
invalid:
- return (display_string (w, vpos, "*invalid*", hpos, 0,
- minendcol, maxendcol));
+ if (frame_title_ptr)
+ hpos = store_frame_title ("*invalid*", minendcol, maxendcol);
+ else
+ hpos = display_string (w, vpos, "*invalid*", -1, hpos, 0, 1,
+ minendcol, maxendcol);
+ return hpos;
}
- end:
if (minendcol > hpos)
- hpos = display_string (w, vpos, "", hpos, 0, minendcol, -1);
+ if (frame_title_ptr)
+ hpos = store_frame_title ("", minendcol, maxendcol);
+ else
+ hpos = display_string (w, vpos, "", 0, hpos, 0, 1, minendcol, maxendcol);
return hpos;
}
\f
register char c;
register int maxwidth;
{
- Lisp_Object obj = Qnil;
+ Lisp_Object obj;
FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
char *decode_mode_spec_buf = (char *) FRAME_TEMP_GLYPHS (f)->total_contents;
+ struct buffer *b = XBUFFER (w->buffer);
+ obj = Qnil;
if (maxwidth > FRAME_WIDTH (f))
maxwidth = FRAME_WIDTH (f);
switch (c)
{
case 'b':
- obj = current_buffer->name;
+ obj = b->name;
#if 0
if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
{
break;
case 'f':
- obj = current_buffer->filename;
+ obj = b->filename;
#if 0
if (NILP (obj))
return "[none]";
- else if (XTYPE (obj) == Lisp_String && XSTRING (obj)->size > maxwidth)
+ else if (STRINGP (obj) && XSTRING (obj)->size > maxwidth)
{
bcopy ("...", decode_mode_spec_buf, 3);
bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
#endif
break;
+ case 'l':
+ {
+ int startpos = marker_position (w->start);
+ int line, linepos, topline;
+ int nlines, junk;
+ Lisp_Object tem;
+ int height = XFASTINT (w->height);
+
+ /* If we decided that this buffer isn't suitable for line numbers,
+ don't forget that too fast. */
+ if (EQ (w->base_line_pos, w->buffer))
+ return "??";
+
+ /* If the buffer is very big, don't waste time. */
+ if (BUF_ZV (b) - BUF_BEGV (b) > line_number_display_limit)
+ {
+ w->base_line_pos = Qnil;
+ w->base_line_number = Qnil;
+ return "??";
+ }
+
+ if (!NILP (w->base_line_number)
+ && !NILP (w->base_line_pos)
+ && XFASTINT (w->base_line_pos) <= marker_position (w->start))
+ {
+ line = XFASTINT (w->base_line_number);
+ linepos = XFASTINT (w->base_line_pos);
+ }
+ else
+ {
+ line = 1;
+ linepos = BUF_BEGV (b);
+ }
+
+ /* Count lines from base line to window start position. */
+ nlines = display_count_lines (linepos, startpos, startpos, &junk);
+
+ topline = nlines + line;
+
+ /* Determine a new base line, if the old one is too close
+ or too far away, or if we did not have one.
+ "Too close" means it's plausible a scroll-down would
+ go back past it. */
+ if (startpos == BUF_BEGV (b))
+ {
+ XFASTINT (w->base_line_number) = topline;
+ XFASTINT (w->base_line_pos) = BUF_BEGV (b);
+ }
+ else if (nlines < height + 25 || nlines > height * 3 + 50
+ || linepos == BUF_BEGV (b))
+ {
+ int limit = BUF_BEGV (b);
+ int position;
+ int distance = (height * 2 + 30) * 200;
+
+ if (startpos - distance > limit)
+ limit = startpos - distance;
+
+ nlines = display_count_lines (startpos, limit,
+ -(height * 2 + 30),
+ &position);
+ /* If we couldn't find the lines we wanted within
+ 200 chars per line,
+ give up on line numbers for this window. */
+ if (position == startpos - distance)
+ {
+ w->base_line_pos = w->buffer;
+ w->base_line_number = Qnil;
+ return "??";
+ }
+
+ XFASTINT (w->base_line_number) = topline - nlines;
+ XFASTINT (w->base_line_pos) = position;
+ }
+
+ /* Now count lines from the start pos to point. */
+ nlines = display_count_lines (startpos, PT, PT, &junk);
+
+ /* Record that we did display the line number. */
+ line_number_displayed = 1;
+
+ /* Make the string to show. */
+ sprintf (decode_mode_spec_buf, "%d", topline + nlines);
+ return decode_mode_spec_buf;
+ }
+ break;
+
case 'm':
- obj = current_buffer->mode_name;
+ obj = b->mode_name;
break;
case 'n':
- if (BEGV > BEG || ZV < Z)
+ if (BUF_BEGV (b) > BUF_BEG (b) || BUF_ZV (b) < BUF_Z (b))
return " Narrow";
break;
case '*':
- if (!NILP (current_buffer->read_only))
+ if (!NILP (b->read_only))
return "%";
- if (MODIFF > current_buffer->save_modified)
+ if (BUF_MODIFF (b) > b->save_modified)
+ return "*";
+ return "-";
+
+ case '+':
+ /* This differs from %* only for a modified read-only buffer. */
+ if (BUF_MODIFF (b) > b->save_modified)
+ return "*";
+ if (!NILP (b->read_only))
+ return "%";
+ return "-";
+
+ case '&':
+ /* This differs from %* in ignoring read-only-ness. */
+ if (BUF_MODIFF (b) > b->save_modified)
return "*";
return "-";
case 's':
/* status of process */
- obj = Fget_buffer_process (Fcurrent_buffer ());
+ obj = Fget_buffer_process (w->buffer);
if (NILP (obj))
return "no process";
+#ifdef subprocesses
obj = Fsymbol_name (Fprocess_status (obj));
+#endif
break;
+ case 't': /* indicate TEXT or BINARY */
+#ifdef MODE_LINE_BINARY_TEXT
+ return MODE_LINE_BINARY_TEXT (b);
+#else
+ return "T";
+#endif
+
case 'p':
{
int pos = marker_position (w->start);
- int total = ZV - BEGV;
+ int total = BUF_ZV (b) - BUF_BEGV (b);
- if (XFASTINT (w->window_end_pos) <= Z - ZV)
+ if (XFASTINT (w->window_end_pos) <= BUF_Z (b) - BUF_ZV (b))
{
- if (pos <= BEGV)
+ if (pos <= BUF_BEGV (b))
return "All";
else
return "Bottom";
}
- else if (pos <= BEGV)
+ else if (pos <= BUF_BEGV (b))
return "Top";
else
{
- total = ((pos - BEGV) * 100 + total - 1) / total;
+ total = ((pos - BUF_BEGV (b)) * 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)
}
}
+ /* Display percentage of size above the bottom of the screen. */
+ case 'P':
+ {
+ int toppos = marker_position (w->start);
+ int botpos = BUF_Z (b) - XFASTINT (w->window_end_pos);
+ int total = BUF_ZV (b) - BUF_BEGV (b);
+
+ if (botpos >= BUF_ZV (b))
+ {
+ if (toppos <= BUF_BEGV (b))
+ return "All";
+ else
+ return "Bottom";
+ }
+ else
+ {
+ total = ((botpos - BUF_BEGV (b)) * 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;
+ if (toppos <= BUF_BEGV (b))
+ sprintf (decode_mode_spec_buf, "Top%2d%%", total);
+ else
+ sprintf (decode_mode_spec_buf, "%2d%%", total);
+ return decode_mode_spec_buf;
+ }
+ }
+
case '%':
return "%";
*p = 0;
return decode_mode_spec_buf;
}
-
+
case '-':
{
register char *p;
return decode_mode_spec_buf;
}
}
-
- if (XTYPE (obj) == Lisp_String)
+
+ if (STRINGP (obj))
return (char *) XSTRING (obj)->data;
else
return "";
}
\f
+/* Search for COUNT instances of a line boundary, which means either a
+ newline or (if selective display enabled) a carriage return.
+ Start at START. If COUNT is negative, search backwards.
+
+ If we find COUNT instances, set *SHORTAGE to zero, and return the
+ position after the COUNTth match. Note that for reverse motion
+ this is not the same as the usual convention for Emacs motion commands.
+
+ If we don't find COUNT instances before reaching the end of the
+ buffer (or the beginning, if scanning backwards), set *SHORTAGE to
+ the number of line boundaries left unfound, and return the end of the
+ buffer we bumped up against. */
+
+static int
+display_scan_buffer (start, count, shortage)
+ int *shortage, start;
+ register int count;
+{
+ int limit = ((count > 0) ? ZV - 1 : BEGV);
+ int direction = ((count > 0) ? 1 : -1);
+
+ register unsigned char *cursor;
+ unsigned char *base;
+
+ register int ceiling;
+ register unsigned char *ceiling_addr;
+
+ /* If we are not in selective display mode,
+ check only for newlines. */
+ if (! (!NILP (current_buffer->selective_display)
+ && !INTEGERP (current_buffer->selective_display)))
+ return scan_buffer ('\n', start, count, shortage, 0);
+
+ /* The code that follows is like scan_buffer
+ but checks for either newline or carriage return. */
+
+ if (shortage != 0)
+ *shortage = 0;
+
+ if (count > 0)
+ while (start != limit + 1)
+ {
+ ceiling = BUFFER_CEILING_OF (start);
+ ceiling = min (limit, ceiling);
+ ceiling_addr = &FETCH_CHAR (ceiling) + 1;
+ base = (cursor = &FETCH_CHAR (start));
+ while (1)
+ {
+ while (*cursor != '\n' && *cursor != 015 && ++cursor != ceiling_addr)
+ ;
+ if (cursor != ceiling_addr)
+ {
+ if (--count == 0)
+ {
+ immediate_quit = 0;
+ return (start + cursor - base + 1);
+ }
+ else
+ if (++cursor == ceiling_addr)
+ break;
+ }
+ else
+ break;
+ }
+ start += cursor - base;
+ }
+ else
+ {
+ start--; /* first character we scan */
+ while (start > limit - 1)
+ { /* we WILL scan under start */
+ ceiling = BUFFER_FLOOR_OF (start);
+ ceiling = max (limit, ceiling);
+ ceiling_addr = &FETCH_CHAR (ceiling) - 1;
+ base = (cursor = &FETCH_CHAR (start));
+ cursor++;
+ while (1)
+ {
+ while (--cursor != ceiling_addr
+ && *cursor != '\n' && *cursor != 015)
+ ;
+ if (cursor != ceiling_addr)
+ {
+ if (++count == 0)
+ {
+ immediate_quit = 0;
+ return (start + cursor - base + 1);
+ }
+ }
+ else
+ break;
+ }
+ start += cursor - base;
+ }
+ }
+
+ if (shortage != 0)
+ *shortage = count * direction;
+ return (start + ((direction == 1 ? 0 : 1)));
+}
+
+/* Count up to N lines starting from FROM.
+ But don't go beyond LIMIT.
+ Return the number of lines thus found (always positive).
+ Store the position after what was found into *POS_PTR. */
+
+static int
+display_count_lines (from, limit, n, pos_ptr)
+ int from, limit, n;
+ int *pos_ptr;
+{
+ int oldbegv = BEGV;
+ int oldzv = ZV;
+ int shortage = 0;
+
+ if (limit < from)
+ BEGV = limit;
+ else
+ ZV = limit;
+
+ *pos_ptr = display_scan_buffer (from, n, &shortage);
+
+ ZV = oldzv;
+ BEGV = oldbegv;
+
+ if (n < 0)
+ /* When scanning backwards, scan_buffer stops *after* the last newline
+ it finds, but does count it. Compensate for that. */
+ return - n - shortage - (*pos_ptr != limit);
+ return n - shortage;
+}
+\f
/* Display STRING on one line of window W, starting at HPOS.
Display at position VPOS. Caller should have done get_display_line.
If VPOS == -1, display it as the current frame's title.
+ LENGTH is the length of STRING, or -1 meaning STRING is null-terminated.
TRUNCATE is GLYPH to display at end if truncated. Zero for none.
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 */
+ OBEY_WINDOW_WIDTH says to put spaces or vertical bars
+ at the place where the current window ends in this line
+ and not display anything beyond there. Otherwise, only MAXCOL
+ controls where to stop output.
+
+ Returns ending hpos. */
static int
-display_string (w, vpos, string, hpos, truncate, mincol, maxcol)
+display_string (w, vpos, string, length, hpos, truncate,
+ obey_window_width, mincol, maxcol)
struct window *w;
unsigned char *string;
+ int length;
int vpos, hpos;
GLYPH truncate;
+ int obey_window_width;
int mincol, maxcol;
{
register int c;
/* 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;
+ int i;
- if (XTYPE (Vstandard_display_table) == Lisp_Vector
+ if (VECTORP (Vstandard_display_table)
&& XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
dp = XVECTOR (Vstandard_display_table);
- if (tab_width <= 0 || tab_width > 20) tab_width = 8;
+ if (tab_width <= 0 || tab_width > 1000) 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)) != FRAME_WIDTH (f))
+ if (obey_window_width)
{
- if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+ end = start + window_width - (truncate != 0);
+
+ if ((window_width + XFASTINT (w->left)) != FRAME_WIDTH (f))
{
- int i;
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+ {
+ int i;
- for (i = 0; i < VERTICAL_SCROLL_BAR_WIDTH; i++)
- *end-- = ' ';
+ for (i = 0; i < FRAME_SCROLL_BAR_COLS (f); i++)
+ *end-- = ' ';
+ }
+ else
+ *end-- = '|';
}
- else
- *end-- = '|';
}
- if (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol)
+ if (! obey_window_width
+ || (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol))
end = desired_glyphs->glyphs[vpos] + maxcol;
+
+ /* Store 0 in charstart for these columns. */
+ for (i = (hpos >= 0 ? hpos : 0); i < end - p1start + hpos; i++)
+ desired_glyphs->charstarts[vpos][i] = 0;
+
if (maxcol >= 0 && mincol > maxcol)
mincol = maxcol;
while (p1 < end)
{
+ if (length == 0)
+ break;
c = *string++;
- if (!c) break;
+ /* Specified length. */
+ if (length >= 0)
+ length--;
+ /* Unspecified length (null-terminated string). */
+ else if (c == 0)
+ break;
+
if (c >= 040 && c < 0177
- && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
+ && (dp == 0 || !VECTORP (DISP_CHAR_VECTOR (dp, c))))
{
if (p1 >= start)
*p1 = c;
}
while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
}
- else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
- p1 = copy_rope (p1, start, DISP_CHAR_VECTOR (dp, c));
+ else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
+ {
+ p1 = copy_part_of_rope (f, p1, start,
+ XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
+ XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
+ 0);
+ }
else if (c < 0200 && ! NILP (buffer_defaults.ctl_arrow))
{
if (p1 >= start)
- *p1 = (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
- ? XINT (DISP_CTRL_GLYPH (dp)) : '^');
+ *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
+ ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
+ 0);
p1++;
if (p1 >= start && p1 < end)
*p1 = c ^ 0100;
else
{
if (p1 >= start)
- *p1 = (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
- ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\');
+ *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
+ ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
+ 0);
p1++;
if (p1 >= start && p1 < end)
*p1 = (c >> 6) + '0';
}
}
- if (c)
+ if (c && length > 0)
{
p1 = end;
- if (truncate) *p1++ = truncate;
+ if (truncate) *p1++ = fix_glyph (f, truncate, 0);
}
else if (mincol >= 0)
{
void
syms_of_xdisp ()
{
+ staticpro (&Qmenu_bar_update_hook);
+ Qmenu_bar_update_hook = intern ("menu-bar-update-hook");
+
staticpro (&last_arrow_position);
staticpro (&last_arrow_string);
last_arrow_position = Qnil;
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;
+
+ DEFVAR_INT ("line-number-display-limit", &line_number_display_limit,
+ "*Maximum buffer size for which line number should be displayed.");
+ line_number_display_limit = 1000000;
+
+ DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
+ "*Non-nil means highlight region even in nonselected windows.");
+ highlight_nonselected_windows = 1;
+
+ DEFVAR_BOOL ("multiple-frames", &multiple_frames,
+ "Non-nil means more than one frame is in use, not counting minibuffer frames.\n\
+Not guaranteed to be accurate except while parsing frame-title-format.");
+
+ DEFVAR_LISP ("frame-title-format", &Vframe_title_format,
+ "Template for displaying the titlebar of visible frames.\n\
+\(Assuming the window manager supports this feature.)\n\
+This variable has the same structure as `mode-line-format' (which see),\n\
+and is used only on frames for which no explicit name has been set\n\
+\(see `modify-frame-parameters').");
+ DEFVAR_LISP ("icon-title-format", &Vicon_title_format,
+ "Template for displaying the titlebar of an iconified frame.\n\
+\(Assuming the window manager supports this feature.)\n\
+This variable has the same structure as `mode-line-format' (which see),\n\
+and is used only on frames for which no explicit name has been set\n\
+\(see `modify-frame-parameters').");
+ Vicon_title_format
+ = Vframe_title_format
+ = Fcons (intern ("multiple-frames"),
+ Fcons (build_string ("%b"),
+ Fcons (Fcons (build_string (""),
+ Fcons (intern ("invocation-name"),
+ Fcons (build_string ("@"),
+ Fcons (intern ("system-name"),
+ Qnil)))),
+ Qnil)));
}
/* initialize the window system */