/* 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.
#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;
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 ();
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;
\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. */
+
void
message1 (m)
char *m;
#endif
if (m)
- echo_area_glyphs = m;
+ {
+ echo_area_glyphs = m;
+ echo_area_glyphs_length = strlen (m);
+ }
else
echo_area_glyphs = previous_echo_glyphs = 0;
}
}
+/* Display an echo area message M with a specified length of LEN chars.
+ This way, null characters can be included. */
+
+void
+message2 (m, len)
+ char *m;
+ int len;
+{
+ if (noninteractive)
+ {
+ if (noninteractive_need_newline)
+ putc ('\n', stderr);
+ noninteractive_need_newline = 0;
+ 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
+ initialized yet. Error messages get reported properly by
+ cmd_error, so this must be just an informative message; toss it. */
+ else if (INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame))
+ {
+#ifdef MULTI_FRAME
+ Lisp_Object minibuf_frame;
+
+ choose_minibuf_frame ();
+ minibuf_frame = WINDOW_FRAME (XWINDOW (minibuf_window));
+ FRAME_SAMPLE_VISIBILITY (XFRAME (minibuf_frame));
+ if (FRAME_VISIBLE_P (selected_frame)
+ && ! FRAME_VISIBLE_P (XFRAME (minibuf_frame)))
+ Fmake_frame_visible (WINDOW_FRAME (XWINDOW (minibuf_window)));
+#endif
+
+ if (m)
+ {
+ echo_area_glyphs = m;
+ echo_area_glyphs_length = len;
+ }
+ else
+ echo_area_glyphs = previous_echo_glyphs = 0;
+
+ do_pending_window_change ();
+ echo_area_display ();
+ update_frame (XFRAME (XWINDOW (minibuf_window)->frame), 1, 1);
+ do_pending_window_change ();
+ }
+}
+
+/* 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;
{
if (m)
{
- {
+ int len;
#ifdef NO_ARG_ARRAY
- int a[3];
- a[0] = a1;
- a[1] = a2;
- a[2] = a3;
+ 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);
get_display_line (f, vpos, 0);
display_string (XWINDOW (minibuf_window), vpos,
echo_area_glyphs ? echo_area_glyphs : "",
+ echo_area_glyphs ? echo_area_glyphs_length : -1,
0, 0, 0, FRAME_WIDTH (f));
/* If desired cursor location is on this line, put it at end of text */
{
get_display_line (f, i, 0);
display_string (XWINDOW (minibuf_window), vpos,
- "", 0, 0, 0, FRAME_WIDTH (f));
+ "", 0, 0, 0, 0, FRAME_WIDTH (f));
}
}
}
previous_echo_glyphs = echo_area_glyphs;
}
\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;
+ }
+
+ 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++;
+ }
+
+ all_windows = update_mode_lines || buffer_shared > 1;
+
+ /* If specs for an arrow have changed, do thorough redisplay
+ to ensure we remove any arrow that should no longer exist. */
+ if (! EQ (Voverlay_arrow_position, last_arrow_position)
+ || ! EQ (Voverlay_arrow_string, last_arrow_string))
+ all_windows = 1, clip_changed = 1;
+
+ /* 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)
+ {
+ FRAME_PTR f = XFRAME (frame);
+
+ if (FRAME_VISIBLE_P (f))
+ update_menu_bars (FRAME_ROOT_WINDOW (f));
+ }
+ }
+ else if (FRAME_VISIBLE_P (selected_frame))
+ update_menu_bar (selected_window);
+}
+\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. */
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))
}
}
\f
+/* Update the menu bar item lists for WINDOW
+ and its subwindows and siblings.
+ This has to be done before we start to fill in any display lines,
+ because it can call eval. */
+
+static void
+update_menu_bars (window)
+ Lisp_Object window;
+{
+ for (; !NILP (window); window = XWINDOW (window)->next)
+ update_menu_bar (window, 0);
+}
+
+/* Update the menu bar item list for window WINDOW and its subwindows. */
+
+static void
+update_menu_bar (window, just_this_one)
+ Lisp_Object window;
+ int just_this_one;
+{
+ register struct window *w = XWINDOW (window);
+ struct buffer *old = current_buffer;
+ FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
+
+ /* If this is a combination window, do its children; that's all. */
+
+ if (!NILP (w->vchild))
+ {
+ update_menu_bars (w->vchild);
+ return;
+ }
+ if (!NILP (w->hchild))
+ {
+ update_menu_bars (w->hchild);
+ return;
+ }
+ if (NILP (w->buffer))
+ abort ();
+
+ if (update_mode_lines)
+ w->update_mode_line = Qt;
+
+ /* 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))
+ {
+ /* 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
+ || update_mode_lines
+ || (XFASTINT (w->last_modified) < MODIFF
+ && (XFASTINT (w->last_modified)
+ <= XBUFFER (w->buffer)->save_modified)))
+ {
+ struct buffer *prev = current_buffer;
+ current_buffer = XBUFFER (w->buffer);
+ FRAME_MENU_BAR_ITEMS (f) = menu_bar_items ();
+ current_buffer = prev;
+#ifdef USE_X_TOOLKIT
+ set_frame_menubar (f);
+#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;
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, 0, width);
}
goto finish_scroll_bars;
- (1 << (SHORTBITS - 1)),
width, hscroll, pos_tab_offset (w, startp));
SET_PT (pos.bufpos);
- if (w != XWINDOW (FRAME_SELECTED_WINDOW (f)))
+ if (w != XWINDOW (selected_window))
Fset_marker (w->pointm, make_number (point), Qnil);
else
{
- lpoint = point;
+ if (current_buffer == old)
+ lpoint = point;
FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left);
FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
}
/* 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);
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));
if (bp.vpos >= height)
{
if (point < bp.bufpos && !bp.contin)
#ifdef USE_TEXT_PROPERTIES
/* The next location where the `invisible' property changes */
int next_invisible;
- Lisp_Object prop, position, endpos;
#endif
/* The face we're currently using. */
&& vpos == XFASTINT (w->top))
{
if (minibuf_prompt)
- hpos = display_string (w, vpos, minibuf_prompt, hpos,
+ hpos = display_string (w, vpos, minibuf_prompt, -1, hpos,
(!truncate ? continuer : truncator),
-1, -1);
minibuf_prompt_width = hpos;
/* if the `invisible' property is set to t, we can skip to
the next property change */
while (pos == next_invisible && pos < end)
- {
- XFASTINT (position) = pos;
- prop = Fget_text_property (position,
- Qinvisible,
- Fcurrent_buffer ());
- endpos = Fnext_single_property_change (position,
- Qinvisible,
- Fcurrent_buffer ());
- if (INTEGERP (endpos))
- next_invisible = XINT (endpos);
- else
- next_invisible = end;
- if (! NILP (prop))
{
- if (pos < point && next_invisible >= point)
- {
- cursor_vpos = vpos;
- cursor_hpos = p1 - startp;
- }
- pos = next_invisible;
+ Lisp_Object position, limit, endpos, prop;
+ XFASTINT (position) = pos;
+ prop = Fget_text_property (position, Qinvisible,
+ Fcurrent_buffer ());
+ /* This is just an estimate to give reasonable
+ performance; nothing should go wrong if it is too small. */
+ 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 < point && next_invisible >= point)
+ {
+ cursor_vpos = vpos;
+ cursor_hpos = p1 - startp;
+ }
+ pos = next_invisible;
+ }
}
- }
if (pos >= end)
break;
#endif
if (pos >= next_face_change && FRAME_X_P (f))
current_face = compute_char_face (f, w, pos,
region_beg, region_end,
- &next_face_change);
+ &next_face_change, pos + 50);
#endif
pause = end;
int maxendcol = FRAME_WIDTH (f);
int hpos = 0;
+#ifndef USE_X_TOOLKIT
if (FRAME_MENU_BAR_LINES (f) <= 0)
return;
get_display_line (f, vpos, 0);
- /* 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
- || update_mode_lines
- || (XFASTINT (w->last_modified) < MODIFF
- && (XFASTINT (w->last_modified)
- <= XBUFFER (w->buffer)->save_modified)))
- {
- struct buffer *prev = current_buffer;
- current_buffer = XBUFFER (w->buffer);
- FRAME_MENU_BAR_ITEMS (f) = menu_bar_items ();
- current_buffer = prev;
- }
-
for (tail = FRAME_MENU_BAR_ITEMS (f); CONSP (tail); tail = XCONS (tail)->cdr)
{
Lisp_Object string;
if (hpos < maxendcol)
hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
XSTRING (string)->data,
+ XSTRING (string)->size,
hpos, 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,
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, maxendcol, -1);
/* 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 */
if (this - 1 != last)
{
register int lim = --this - last + hpos;
- hpos = display_string (w, vpos, last, hpos, 0, hpos,
+ hpos = display_string (w, vpos, last, -1, hpos, 0, hpos,
min (lim, maxendcol));
}
else /* c == '%' */
hpos = display_string (w, vpos,
decode_mode_spec (w, c,
maxendcol - hpos),
+ -1,
hpos, 0, spec_width, maxendcol);
}
}
don't check for % within it. */
if (XTYPE (tem) == Lisp_String)
hpos = display_string (w, vpos, XSTRING (tem)->data,
+ XSTRING (tem)->size,
hpos, 0, minendcol, maxendcol);
/* Give up right away for nil or t. */
else if (!EQ (tem, elt))
default:
invalid:
- return (display_string (w, vpos, "*invalid*", hpos, 0,
+ return (display_string (w, vpos, "*invalid*", -1, hpos, 0,
minendcol, maxendcol));
}
end:
if (minendcol > hpos)
- hpos = display_string (w, vpos, "", hpos, 0, minendcol, -1);
+ hpos = display_string (w, vpos, "", 0, hpos, 0, minendcol, -1);
return hpos;
}
\f
obj = Fget_buffer_process (Fcurrent_buffer ());
if (NILP (obj))
return "no process";
+#ifdef subprocesses
obj = Fsymbol_name (Fprocess_status (obj));
+#endif
break;
+ case 't': /* indicate TEXT or BINARY */
+#ifdef MSDOS
+ decode_mode_spec_buf[0]
+ = NILP (current_buffer->buffer_file_type) ? "T" : "B";
+ decode_mode_spec_buf[1] = 0;
+ return decode_mode_spec_buf;
+#else /* not MSDOS */
+ return "T";
+#endif /* not MSDOS */
+
case 'p':
{
int pos = marker_position (w->start);
/* 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.
Returns ending hpos */
static int
-display_string (w, vpos, string, hpos, truncate, mincol, maxcol)
+display_string (w, vpos, string, length, hpos, truncate, mincol, maxcol)
struct window *w;
unsigned char *string;
+ int length;
int vpos, hpos;
GLYPH truncate;
int 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))
{
}
}
- if (c)
+ if (c && length > 0)
{
p1 = end;
if (truncate) *p1++ = truncate;