/* Display generation from window structure and buffer text.
- Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 97, 98, 99
+ Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 97, 98, 99, 2000
Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <config.h>
#include <stdio.h>
#include "lisp.h"
+#include "keyboard.h"
#include "frame.h"
#include "window.h"
#include "termchar.h"
#include "disptab.h"
#include "termhooks.h"
#include "intervals.h"
-#include "keyboard.h"
#include "coding.h"
#include "process.h"
#include "region-cache.h"
#define INFINITY 10000000
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
-extern void set_frame_menubar ();
+extern void set_frame_menubar P_ ((struct frame *f, int, int));
extern int pending_menu_activation;
#endif
static Lisp_Object Vwindow_size_change_functions;
-Lisp_Object Qmenu_bar_update_hook;
+Lisp_Object Qmenu_bar_update_hook, Vmenu_bar_update_hook;
/* Nonzero if overlay arrow has been displayed once in this window. */
Lisp_Object Vmessage_log_max;
+/* The name of the *Messages* buffer, a string. */
+
+static Lisp_Object Vmessages_buffer_name;
+
/* Current, index 0, and last displayed echo area message. Either
buffers from echo_buffers, or nil to indicate no message. */
specifying a fraction of the available height, or an integer
specifying a number of lines. */
-static Lisp_Object Vmax_mini_window_height;
+Lisp_Object Vmax_mini_window_height;
+
+/* Non-zero means messages should be displayed with truncated
+ lines instead of being continued. */
+
+int message_truncate_lines;
+Lisp_Object Qmessage_truncate_lines;
/* Non-zero means we want a hollow cursor in windows that are not
selected. Zero means there's no cursor in such windows. */
#define TEXT_PROP_DISTANCE_LIMIT 100
+#if GLYPH_DEBUG
+
/* Non-zero means print traces of redisplay if compiled with
GLYPH_DEBUG != 0. */
-#if GLYPH_DEBUG
int trace_redisplay_p;
-#endif
+#endif /* GLYPH_DEBUG */
+
+#ifdef DEBUG_TRACE_MOVE
+/* Non-zero means trace with TRACE_MOVE to stderr. */
+int trace_move;
+
+#define TRACE_MOVE(x) if (trace_move) fprintf x; else (void) 0
+#else
+#define TRACE_MOVE(x) (void) 0
+#endif
+
/* Non-zero means automatically scroll windows horizontally to make
point visible. */
\f
/* Function prototypes. */
+static int redisplay_mode_lines P_ ((Lisp_Object, int));
+static char *decode_mode_spec_coding P_ ((Lisp_Object, char *, int));
+static int invisible_text_between_p P_ ((struct it *, int, int));
+static int next_element_from_ellipsis P_ ((struct it *));
+static void pint2str P_ ((char *, int, int));
+static struct text_pos run_window_scroll_functions P_ ((Lisp_Object,
+ struct text_pos));
+static void reconsider_clip_changes P_ ((struct window *, struct buffer *));
+static int text_outside_line_unchanged_p P_ ((struct window *, int, int));
+static void store_frame_title_char P_ ((char));
+static int store_frame_title P_ ((unsigned char *, int, int));
+static void x_consider_frame_title P_ ((Lisp_Object));
+static void handle_stop P_ ((struct it *));
+static int tool_bar_lines_needed P_ ((struct frame *));
+static int single_display_prop_intangible_p P_ ((Lisp_Object));
static void ensure_echo_area_buffers P_ ((void));
static struct glyph_row *row_containing_pos P_ ((struct window *, int,
struct glyph_row *,
struct glyph_row *));
static Lisp_Object unwind_with_echo_area_buffer P_ ((Lisp_Object));
static Lisp_Object with_echo_area_buffer_unwind_data P_ ((struct window *));
+static int with_echo_area_buffer P_ ((struct window *, int,
+ int (*) (EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT),
+ EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
static void clear_garbaged_frames P_ ((void));
-static int current_message_1 P_ ((Lisp_Object *));
-static int truncate_message_1 P_ ((int));
-static int set_message_1 P_ ((char *s, Lisp_Object, int, int));
+static int current_message_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
+static int truncate_message_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
+static int set_message_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
static int display_echo_area P_ ((struct window *));
-static int display_echo_area_1 P_ ((struct window *));
+static int display_echo_area_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
+static int resize_mini_window_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
static Lisp_Object unwind_redisplay P_ ((Lisp_Object));
static int string_char_and_length P_ ((unsigned char *, int, int *));
static struct text_pos display_prop_end P_ ((struct it *, Lisp_Object,
struct text_pos));
static int compute_window_start_on_continuation_line P_ ((struct window *));
static Lisp_Object eval_handler P_ ((Lisp_Object));
-static Lisp_Object eval_form P_ ((Lisp_Object));
static void insert_left_trunc_glyphs P_ ((struct it *));
static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *));
static void extend_face_to_end_of_line P_ ((struct it *));
static int append_space P_ ((struct it *, int));
static void make_cursor_line_fully_visible P_ ((struct window *));
static int try_scrolling P_ ((Lisp_Object, int, int, int, int));
+static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *));
static int trailing_whitespace_p P_ ((int));
static int message_log_check_duplicate P_ ((int, int, int, int));
int invisible_p P_ ((Lisp_Object, Lisp_Object));
static int try_window_reusing_current_matrix P_ ((struct window *));
static int try_window_id P_ ((struct window *));
static int display_line P_ ((struct it *));
-static void display_mode_lines P_ ((struct window *));
+static int display_mode_lines P_ ((struct window *));
static void display_mode_line P_ ((struct window *, enum face_id,
Lisp_Object));
static int display_mode_element P_ ((struct it *, int, int, int, Lisp_Object));
Lisp form evaluation
***********************************************************************/
-/* Error handler for eval_form. */
+/* Error handler for eval_form and call_function. */
static Lisp_Object
eval_handler (arg)
/* Evaluate SEXPR and return the result, or nil if something went
wrong. */
-static Lisp_Object
+Lisp_Object
eval_form (sexpr)
Lisp_Object sexpr;
{
int count = specpdl_ptr - specpdl;
+ struct gcpro gcpro1;
Lisp_Object val;
+
+ GCPRO1 (sexpr);
specbind (Qinhibit_redisplay, Qt);
val = internal_condition_case_1 (Feval, sexpr, Qerror, eval_handler);
+ UNGCPRO;
+ return unbind_to (count, val);
+}
+
+
+/* Call function ARGS[0] with arguments ARGS[1] to ARGS[NARGS - 1].
+ Return the result, or nil if something went wrong. */
+
+Lisp_Object
+call_function (nargs, args)
+ int nargs;
+ Lisp_Object *args;
+{
+ int count = specpdl_ptr - specpdl;
+ Lisp_Object val;
+ struct gcpro gcpro1;
+
+ GCPRO1 (args[0]);
+ gcpro1.nvars = nargs;
+ specbind (Qinhibit_redisplay, Qt);
+ val = internal_condition_case_2 (Ffuncall, nargs, args, Qerror,
+ eval_handler);
+ UNGCPRO;
return unbind_to (count, val);
}
\003, or in the middle of an overlay string). In this case
move_it_to above will not have taken us to the start of
the continuation line but to the end of the continued line. */
- if (!it->truncate_lines_p && it->current_x > 0)
+ if (!it->truncate_lines_p)
{
- if (it->current.dpvec_index >= 0
- || it->current.overlay_string_index >= 0)
+ if (it->current_x > 0)
{
- set_iterator_to_next (it);
- move_it_in_display_line_to (it, -1, -1, 0);
+ if (it->current.dpvec_index >= 0
+ || it->current.overlay_string_index >= 0)
+ {
+ set_iterator_to_next (it);
+ move_it_in_display_line_to (it, -1, -1, 0);
+ }
+
+ it->continuation_lines_width += it->current_x;
}
- it->continuation_lines_width += it->current_x;
+
+ /* We're starting a new display line, not affected by the
+ height of the continued line, so clear the appropriate
+ fields in the iterator structure. */
+ it->max_ascent = it->max_descent = 0;
+ it->max_phys_ascent = it->max_phys_descent = 0;
}
it->current_y = first_y;
it->dpvec = NULL;
it->current.dpvec_index = -1;
+ it->add_overlay_start = 0;
do
{
for (p = it_props; p->handler; ++p)
{
handled = p->handler (it);
-
+
if (handled == HANDLED_RECOMPUTE_PROPS)
break;
else if (handled == HANDLED_RETURN)
/* Get all overlays at the given position. */
len = 10;
overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
- noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL);
+ noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
if (noverlays > len)
{
len = noverlays;
overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
- noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL);
+ noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
}
/* If any of these overlays ends before endpos,
if (!STRINGP (it->string)
&& it->s == NULL
&& !NILP (Vfontification_functions)
+ && !NILP (Vrun_hooks)
&& (pos = make_number (IT_CHARPOS (*it)),
prop = Fget_char_property (pos, Qfontified, Qnil),
NILP (prop)))
{
- Lisp_Object args[2];
+ int count = specpdl_ptr - specpdl;
+ Lisp_Object val;
+
+ val = Vfontification_functions;
+ specbind (Qfontification_functions, Qnil);
+ specbind (Qafter_change_functions, Qnil);
+
+ if (!CONSP (val) || EQ (XCAR (val), Qlambda))
+ call1 (val, pos);
+ else
+ {
+ Lisp_Object globals, fn;
+ struct gcpro gcpro1, gcpro2;
- /* Run the hook functions. */
- args[0] = Qfontification_functions;
- args[1] = pos;
- Frun_hook_with_args (2, args);
+ globals = Qnil;
+ GCPRO2 (val, globals);
+
+ for (; CONSP (val); val = XCDR (val))
+ {
+ fn = XCAR (val);
+
+ if (EQ (fn, Qt))
+ {
+ /* A value of t indicates this hook has a local
+ binding; it means to run the global binding too.
+ In a global value, t should not occur. If it
+ does, we must ignore it to avoid an endless
+ loop. */
+ for (globals = Fdefault_value (Qfontification_functions);
+ CONSP (globals);
+ globals = XCDR (globals))
+ {
+ fn = XCAR (globals);
+ if (!EQ (fn, Qt))
+ call1 (fn, pos);
+ }
+ }
+ else
+ call1 (fn, pos);
+ }
+
+ UNGCPRO;
+ }
+
+ unbind_to (count, Qnil);
/* Return HANDLED_RECOMPUTE_PROPS only if function fontified
something. This avoids an endless loop if they failed to
= TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (prop);
handled = HANDLED_RECOMPUTE_PROPS;
+ it->add_overlay_start = IT_CHARPOS (*it);
/* Loop skipping over invisible text. The loop is left at
ZV or with IT on the first char being visible again. */
Lisp_Object end;
struct text_pos end_pos;
- end = next_single_char_property_change (make_number (CHARPOS (start_pos)),
- Qdisplay, object, Qnil);
+ end = Fnext_single_char_property_change (make_number (CHARPOS (start_pos)),
+ Qdisplay, object, Qnil);
CHARPOS (end_pos) = XFASTINT (end);
if (STRINGP (object))
compute_string_pos (&end_pos, start_pos, it->string);
{
Lisp_Object value;
int space_or_image_found_p = 0;
-
Lisp_Object form;
/* If PROP is a list of the form `(when FORM . VALUE)', FORM is
steps = - steps;
it->face_id = smaller_face (it->f, it->face_id, steps);
}
- else if (SYMBOLP (it->font_height))
+ else if (FUNCTIONP (it->font_height))
{
/* Call function with current height as argument.
Value is the new height. */
- Lisp_Object form, height;
- struct gcpro gcpro1;
+ Lisp_Object args[2], height;
+
+ args[0] = it->font_height;
+ args[1] = face->lface[LFACE_HEIGHT_INDEX];
+ height = call_function (2, args);
- height = face->lface[LFACE_HEIGHT_INDEX];
- form = Fcons (it->font_height, Fcons (height, Qnil));
- GCPRO1 (form);
- height = eval_form (form);
if (NUMBERP (height))
new_height = XFLOATINT (height);
- UNGCPRO;
}
else if (NUMBERP (it->font_height))
{
}
+/* Check if PROP is a display sub-property value whose text should be
+ treated as intangible. */
+
+static int
+single_display_prop_intangible_p (prop)
+ Lisp_Object prop;
+{
+ /* Skip over `when FORM'. */
+ if (CONSP (prop) && EQ (XCAR (prop), Qwhen))
+ {
+ prop = XCDR (prop);
+ if (!CONSP (prop))
+ return 0;
+ prop = XCDR (prop);
+ }
+
+ if (!CONSP (prop))
+ return 0;
+
+ /* Skip over `margin LOCATION'. If LOCATION is in the margins,
+ we don't need to treat text as intangible. */
+ if (EQ (XCAR (prop), Qmargin))
+ {
+ prop = XCDR (prop);
+ if (!CONSP (prop))
+ return 0;
+
+ prop = XCDR (prop);
+ if (!CONSP (prop)
+ || EQ (XCAR (prop), Qleft_margin)
+ || EQ (XCAR (prop), Qright_margin))
+ return 0;
+ }
+
+ return CONSP (prop) && EQ (XCAR (prop), Qimage);
+}
+
+
+/* Check if PROP is a display property value whose text should be
+ treated as intangible. */
+
+int
+display_prop_intangible_p (prop)
+ Lisp_Object prop;
+{
+ if (CONSP (prop)
+ && CONSP (XCAR (prop))
+ && !EQ (Qmargin, XCAR (XCAR (prop))))
+ {
+ /* A list of sub-properties. */
+ while (CONSP (prop))
+ {
+ if (single_display_prop_intangible_p (XCAR (prop)))
+ return 1;
+ prop = XCDR (prop);
+ }
+ }
+ else if (VECTORP (prop))
+ {
+ /* A vector of sub-properties. */
+ int i;
+ for (i = 0; i < XVECTOR (prop)->size; ++i)
+ if (single_display_prop_intangible_p (XVECTOR (prop)->contents[i]))
+ return 1;
+ }
+ else
+ return single_display_prop_intangible_p (prop);
+
+ return 0;
+}
+
\f
/***********************************************************************
`composition' property
struct overlay_entry
{
+ Lisp_Object overlay;
Lisp_Object string;
int priority;
int after_string_p;
handle_overlay_change (it)
struct it *it;
{
- /* Overlays are handled in current_buffer only. */
- if (STRINGP (it->string))
- return HANDLED_NORMALLY;
+ if (!STRINGP (it->string) && get_overlay_strings (it))
+ return HANDLED_RECOMPUTE_PROPS;
else
- return (get_overlay_strings (it)
- ? HANDLED_RECOMPUTE_PROPS
- : HANDLED_NORMALLY);
+ return HANDLED_NORMALLY;
}
SET_TEXT_POS (it->current.string_pos, -1, -1);
it->n_overlay_strings = 0;
it->method = next_element_from_buffer;
+
+ /* If we're at the end of the buffer, record that we have
+ processed the overlay strings there already, so that
+ next_element_from_buffer doesn't try it again. */
+ if (IT_CHARPOS (*it) >= it->end_charpos)
+ it->overlay_strings_at_end_processed_p = 1;
}
else
{
comparison function for qsort in load_overlay_strings. Overlay
strings for the same position are sorted so that
- 1. All after-strings come in front of before-strings.
+ 1. All after-strings come in front of before-strings, except
+ when they come from the same overlay.
2. Within after-strings, strings are sorted so that overlay strings
from overlays with higher priorities come first.
int result;
if (entry1->after_string_p != entry2->after_string_p)
- /* Let after-strings appear in front of before-strings. */
- result = entry1->after_string_p ? -1 : 1;
+ {
+ /* Let after-strings appear in front of before-strings if
+ they come from different overlays. */
+ if (EQ (entry1->overlay, entry2->overlay))
+ result = entry1->after_string_p ? 1 : -1;
+ else
+ result = entry1->after_string_p ? -1 : 1;
+ }
else if (entry1->after_string_p)
/* After-strings sorted in order of decreasing priority. */
result = entry2->priority - entry1->priority;
strings that have already been loaded by previous calls to this
function.
+ IT->add_overlay_start contains an additional overlay start
+ position to consider for taking overlay strings from, if non-zero.
+ This position comes into play when the overlay has an `invisible'
+ property, and both before and after-strings. When we've skipped to
+ the end of the overlay, because of its `invisible' property, we
+ nevertheless want its before-string to appear.
+ IT->add_overlay_start will contain the overlay start position
+ in this case.
+
Overlay strings are sorted so that after-string strings come in
front of before-string strings. Within before and after-strings,
strings are sorted by overlay priority. See also function
} \
\
entries[n].string = (STRING); \
+ entries[n].overlay = (OVERLAY); \
priority = Foverlay_get ((OVERLAY), Qpriority); \
- entries[n].priority \
- = INTEGERP (priority) ? XFASTINT (priority) : 0; \
+ entries[n].priority = INTEGERP (priority) ? XINT (priority) : 0; \
entries[n].after_string_p = (AFTER_P); \
++n; \
} \
while (0)
/* Process overlay before the overlay center. */
- for (ov = current_buffer->overlays_before;
- CONSP (ov);
- ov = XCDR (ov))
+ for (ov = current_buffer->overlays_before; CONSP (ov); ov = XCDR (ov))
{
overlay = XCAR (ov);
xassert (OVERLAYP (overlay));
/* Skip this overlay if it doesn't start or end at IT's current
position. */
- if (end != IT_CHARPOS (*it) && start != IT_CHARPOS (*it))
+ if (end != IT_CHARPOS (*it)
+ && start != IT_CHARPOS (*it)
+ && it->add_overlay_start != IT_CHARPOS (*it))
continue;
/* Skip this overlay if it doesn't apply to IT->w. */
continue;
/* If overlay has a non-empty before-string, record it. */
- if (start == IT_CHARPOS (*it)
+ if ((start == IT_CHARPOS (*it)
+ || start == it->add_overlay_start)
&& (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str))
&& XSTRING (str)->size)
RECORD_OVERLAY_STRING (overlay, str, 0);
}
/* Process overlays after the overlay center. */
- for (ov = current_buffer->overlays_after;
- CONSP (ov);
- ov = XCDR (ov))
+ for (ov = current_buffer->overlays_after; CONSP (ov); ov = XCDR (ov))
{
overlay = XCAR (ov);
xassert (OVERLAYP (overlay));
/* Skip this overlay if it doesn't start or end at IT's current
position. */
- if (end != IT_CHARPOS (*it) && start != IT_CHARPOS (*it))
+ if (end != IT_CHARPOS (*it)
+ && start != IT_CHARPOS (*it)
+ && it->add_overlay_start != IT_CHARPOS (*it))
continue;
/* Skip this overlay if it doesn't apply to IT->w. */
continue;
/* If overlay has a non-empty before-string, record it. */
- if (start == IT_CHARPOS (*it)
+ if ((start == IT_CHARPOS (*it)
+ || start == it->add_overlay_start)
&& (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str))
&& XSTRING (str)->size)
RECORD_OVERLAY_STRING (overlay, str, 0);
#undef RECORD_OVERLAY_STRING
/* Sort entries. */
- qsort (entries, n, sizeof *entries, compare_overlay_entries);
+ if (n)
+ qsort (entries, n, sizeof *entries, compare_overlay_entries);
/* Record the total number of strings to process. */
it->n_overlay_strings = n;
j = it->current.overlay_string_index;
while (i < OVERLAY_STRING_CHUNK_SIZE && j < n)
it->overlay_strings[i++] = entries[j++].string;
-
+
CHECK_IT (it);
}
/* The entry may contain a face id to use. Such a face id is
the id of a Lisp face, not a realized face. A face id of
- zero means no face. */
+ zero means no face is specified. */
lface_id = FAST_GLYPH_FACE (g);
if (lface_id)
{
+ /* The function returns -1 if lface_id is invalid. */
int face_id = ascii_face_of_lisp_face (it->f, lface_id);
if (face_id >= 0)
- {
- it->face_id = face_id;
- }
+ it->face_id = face_id;
}
}
else
while (1)
{
- int x, i;
+ int x, i, ascent = 0, descent = 0;
/* Stop when ZV or TO_CHARPOS reached. */
if (!get_next_display_element (it)
x-position before this display element in case it does not
fit on the line. */
x = it->current_x;
+
+ /* Remember the line height so far in case the next element doesn't
+ fit on the line. */
+ if (!it->truncate_lines_p)
+ {
+ ascent = it->max_ascent;
+ descent = it->max_descent;
+ }
+
PRODUCE_GLYPHS (it);
if (it->area != TEXT_AREA)
set_iterator_to_next (it);
}
else
- it->current_x = x;
-
+ {
+ it->current_x = x;
+ it->max_ascent = ascent;
+ it->max_descent = descent;
+ }
+
+ TRACE_MOVE ((stderr, "move_it_in: continued at %d\n",
+ IT_CHARPOS (*it)));
result = MOVE_LINE_CONTINUED;
break;
}
{
enum move_it_result skip, skip2 = MOVE_X_REACHED;
int line_height;
+ int reached = 0;
- while (1)
+ for (;;)
{
if (op & MOVE_TO_VPOS)
{
if ((op & (MOVE_TO_X | MOVE_TO_POS)) == 0)
{
if (it->vpos == to_vpos)
- break;
- skip = move_it_in_display_line_to (it, -1, -1, 0);
+ {
+ reached = 1;
+ break;
+ }
+ else
+ skip = move_it_in_display_line_to (it, -1, -1, 0);
}
else
{
/* TO_VPOS >= 0 means stop at TO_X in the line at
TO_VPOS, or at TO_POS, whichever comes first. */
+ if (it->vpos == to_vpos)
+ {
+ reached = 2;
+ break;
+ }
+
skip = move_it_in_display_line_to (it, to_charpos, to_x, op);
if (skip == MOVE_POS_MATCH_OR_ZV || it->vpos == to_vpos)
- break;
+ {
+ reached = 3;
+ break;
+ }
else if (skip == MOVE_X_REACHED && it->vpos != to_vpos)
{
/* We have reached TO_X but not in the line we want. */
skip = move_it_in_display_line_to (it, to_charpos,
-1, MOVE_TO_POS);
if (skip == MOVE_POS_MATCH_OR_ZV)
- break;
+ {
+ reached = 4;
+ break;
+ }
}
}
}
else if (op & MOVE_TO_Y)
{
struct it it_backup;
- int done_p;
/* TO_Y specified means stop at TO_X in the line containing
TO_Y---or at TO_CHARPOS if this is reached first. The
/* If TO_CHARPOS is reached or ZV, we don't have to do more. */
if (skip == MOVE_POS_MATCH_OR_ZV)
- break;
+ {
+ reached = 5;
+ break;
+ }
/* If TO_X was reached, we would like to know whether TO_Y
is in the line. This can only be said if we know the
total line height which requires us to scan the rest of
the line. */
- done_p = 0;
if (skip == MOVE_X_REACHED)
{
it_backup = *it;
+ TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it)));
skip2 = move_it_in_display_line_to (it, to_charpos, -1,
op & MOVE_TO_POS);
+ TRACE_MOVE ((stderr, "move_it: to %d\n", IT_CHARPOS (*it)));
}
/* Now, decide whether TO_Y is in this line. */
line_height = it->max_ascent + it->max_descent;
+ TRACE_MOVE ((stderr, "move_it: line_height = %d\n", line_height));
if (to_y >= it->current_y
&& to_y < it->current_y + line_height)
we scanned too far. We have to restore IT's settings
to the ones before skipping. */
*it = it_backup;
- done_p = 1;
+ reached = 6;
}
else if (skip == MOVE_X_REACHED)
{
skip = skip2;
if (skip == MOVE_POS_MATCH_OR_ZV)
- done_p = 1;
+ reached = 7;
}
- if (done_p)
+ if (reached)
break;
}
else
switch (skip)
{
case MOVE_POS_MATCH_OR_ZV:
- return;
+ reached = 8;
+ goto out;
case MOVE_NEWLINE_OR_CR:
set_iterator_to_next (it);
reseat_at_next_visible_line_start (it, 0);
if ((op & MOVE_TO_POS) != 0
&& IT_CHARPOS (*it) > to_charpos)
- goto out;
+ {
+ reached = 9;
+ goto out;
+ }
break;
case MOVE_LINE_CONTINUED:
last_max_ascent = it->max_ascent;
it->max_ascent = it->max_descent = 0;
}
- out:;
+
+ out:
+
+ TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached));
}
MOVE_TO_POS | MOVE_TO_VPOS);
xassert (IT_CHARPOS (*it) >= BEGV);
line_height = it2.max_ascent + it2.max_descent;
+
move_it_to (&it2, start_pos, -1, -1, -1, MOVE_TO_POS);
xassert (IT_CHARPOS (*it) >= BEGV);
h = it2.current_y - it->current_y;
move_it_vertically_backward (it, -dy);
else if (dy > 0)
{
+ TRACE_MOVE ((stderr, "move_it_v: from %d, %d\n", IT_CHARPOS (*it), dy));
move_it_to (it, ZV, -1, it->current_y + dy, -1,
MOVE_TO_POS | MOVE_TO_Y);
+ TRACE_MOVE ((stderr, "move_it_v: to %d\n", IT_CHARPOS (*it)));
/* If buffer ends in ZV without a newline, move to the start of
the line to satisfy the post-condition. */
invisible_found_p = 1;
else
{
- limit = next_single_char_property_change (make_number (start_charpos),
- Qinvisible, Qnil,
- make_number (end_charpos));
+ limit = Fnext_single_char_property_change (make_number (start_charpos),
+ Qinvisible, Qnil,
+ make_number (end_charpos));
invisible_found_p = XFASTINT (limit) < end_charpos;
}
old_deactivate_mark = Vdeactivate_mark;
oldbuf = current_buffer;
- Fset_buffer (Fget_buffer_create (build_string ("*Messages*")));
+ Fset_buffer (Fget_buffer_create (Vmessages_buffer_name));
current_buffer->undo_list = Qt;
oldpoint = Fpoint_marker ();
|| NILP (XBUFFER (echo_buffer[i])->name))
{
char name[30];
+ Lisp_Object old_buffer;
+ int j;
+
+ old_buffer = echo_buffer[i];
sprintf (name, " *Echo Area %d*", i);
echo_buffer[i] = Fget_buffer_create (build_string (name));
+ XBUFFER (echo_buffer[i])->truncate_lines = Qnil;
+
+ for (j = 0; j < 2; ++j)
+ if (EQ (old_buffer, echo_area_buffer[j]))
+ echo_area_buffer[j] = echo_buffer[i];
}
}
-/* Call FN with args A1..A5 with either the current or last displayed
+/* Call FN with args A1..A4 with either the current or last displayed
echo_area_buffer as current buffer.
WHICH zero means use the current message buffer
Value is what FN returns. */
static int
-with_echo_area_buffer (w, which, fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
+with_echo_area_buffer (w, which, fn, a1, a2, a3, a4)
struct window *w;
int which;
- int (*fn) ();
- int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
+ int (*fn) P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
+ EMACS_INT a1;
+ Lisp_Object a2;
+ EMACS_INT a3, a4;
{
Lisp_Object buffer;
int this_one, the_other, clear_buffer_p, rc;
w->buffer = buffer;
set_marker_both (w->pointm, buffer, BEG, BEG_BYTE);
}
- current_buffer->truncate_lines = Qnil;
+
current_buffer->undo_list = Qt;
current_buffer->read_only = Qnil;
xassert (BEGV >= BEG);
xassert (ZV <= Z && ZV >= BEGV);
- rc = fn (a1, a2, a3, a4, a5);
+ rc = fn (a1, a2, a3, a4);
xassert (BEGV >= BEG);
xassert (ZV <= Z && ZV >= BEGV);
Fraise_frame (WINDOW_FRAME (XWINDOW (mini_window)));
}
+ message_log_maybe_newline ();
message_buf_print = 1;
}
else
window_height_changed_p
= with_echo_area_buffer (w, display_last_displayed_message_p,
- (int (*) ()) display_echo_area_1, w);
+ display_echo_area_1,
+ (EMACS_INT) w, Qnil, 0, 0);
if (no_message_p)
echo_area_buffer[i] = Qnil;
/* Helper for display_echo_area. Display the current buffer which
- contains the current echo area message in window W, a mini-window.
+ contains the current echo area message in window W, a mini-window,
+ a pointer to which is passed in A1. A2..A4 are currently not used.
Change the height of W so that all of the message is displayed.
Value is non-zero if height of W was changed. */
static int
-display_echo_area_1 (w)
- struct window *w;
+display_echo_area_1 (a1, a2, a3, a4)
+ EMACS_INT a1;
+ Lisp_Object a2;
+ EMACS_INT a3, a4;
{
+ struct window *w = (struct window *) a1;
Lisp_Object window;
struct text_pos start;
int window_height_changed_p = 0;
struct window *w = XWINDOW (echo_area_window);
int resized_p;
- resized_p = with_echo_area_buffer (w, 0,
- (int (*) ()) resize_mini_window,
- w, 1);
+ resized_p = with_echo_area_buffer (w, 0, resize_mini_window_1,
+ (EMACS_INT) w, Qnil, 0, 0);
if (resized_p)
{
++windows_or_buffers_changed;
}
+/* Callback function for with_echo_area_buffer, when used from
+ resize_echo_area_axactly. A1 contains a pointer to the window to
+ resize, A2 to A4 are not used. Value is what resize_mini_window
+ returns. */
+
+static int
+resize_mini_window_1 (a1, a2, a3, a4)
+ EMACS_INT a1;
+ Lisp_Object a2;
+ EMACS_INT a3, a4;
+{
+ return resize_mini_window ((struct window *) a1, 1);
+}
+
+
/* Resize mini-window W to fit the size of its contents. EXACT:P
means size the window exactly to the size needed. Otherwise, it's
only enlarged until W's buffer is empty. Value is non-zero if
max_height = min (total_height, max_height);
/* Find out the height of the text in the window. */
- last_height = 0;
- move_it_to (&it, ZV, -1, -1, -1, MOVE_TO_POS);
- if (it.max_ascent == 0 && it.max_descent == 0)
- height = it.current_y + last_height;
+ if (it.truncate_lines_p)
+ height = 1;
else
- height = it.current_y + it.max_ascent + it.max_descent;
- height = (height + unit - 1) / unit;
+ {
+ last_height = 0;
+ move_it_to (&it, ZV, -1, -1, -1, MOVE_TO_POS);
+ if (it.max_ascent == 0 && it.max_descent == 0)
+ height = it.current_y + last_height;
+ else
+ height = it.current_y + it.max_ascent + it.max_descent;
+ height -= it.extra_line_spacing;
+ height = (height + unit - 1) / unit;
+ }
/* Compute a suitable window start. */
if (height > max_height)
msg = Qnil;
else
{
- with_echo_area_buffer (0, 0, (int (*) ()) current_message_1, &msg);
+ with_echo_area_buffer (0, 0, current_message_1,
+ (EMACS_INT) &msg, Qnil, 0, 0);
if (NILP (msg))
echo_area_buffer[0] = Qnil;
}
static int
-current_message_1 (msg)
- Lisp_Object *msg;
+current_message_1 (a1, a2, a3, a4)
+ EMACS_INT a1;
+ Lisp_Object a2;
+ EMACS_INT a3, a4;
{
+ Lisp_Object *msg = (Lisp_Object *) a1;
+
if (Z > BEG)
*msg = make_buffer_string (BEG, Z, 1);
else
{
struct frame *sf = SELECTED_FRAME ();
if (FRAME_MESSAGE_BUF (sf))
- with_echo_area_buffer (0, 0, (int (*) ()) truncate_message_1, nchars);
+ with_echo_area_buffer (0, 0, truncate_message_1, nchars, Qnil, 0, 0);
}
}
message to at most NCHARS characters. */
static int
-truncate_message_1 (nchars)
- int nchars;
+truncate_message_1 (nchars, a2, a3, a4)
+ EMACS_INT nchars;
+ Lisp_Object a2;
+ EMACS_INT a3, a4;
{
if (BEG + nchars < Z)
del_range (BEG + nchars, Z);
= ((s && multibyte_p)
|| (STRINGP (string) && STRING_MULTIBYTE (string)));
- with_echo_area_buffer (0, -1, (int (*) ()) set_message_1,
- s, string, nbytes, multibyte_p);
+ with_echo_area_buffer (0, -1, set_message_1,
+ (EMACS_INT) s, string, nbytes, multibyte_p);
message_buf_print = 0;
}
/* Helper function for set_message. Arguments have the same meaning
- as there. This function is called with the echo area buffer being
+ as there, with A1 corresponding to S and A2 corresponding to STRING
+ This function is called with the echo area buffer being
current. */
static int
-set_message_1 (s, string, nbytes, multibyte_p)
- char *s;
- Lisp_Object string;
- int nbytes, multibyte_p;
+set_message_1 (a1, a2, nbytes, multibyte_p)
+ EMACS_INT a1;
+ Lisp_Object a2;
+ EMACS_INT nbytes, multibyte_p;
{
+ char *s = (char *) a1;
+ Lisp_Object string = a2;
+
xassert (BEG == Z);
/* Change multibyteness of the echo buffer appropriately. */
!= !NILP (current_buffer->enable_multibyte_characters))
Fset_buffer_multibyte (message_enable_multibyte ? Qt : Qnil);
+ current_buffer->truncate_lines = message_truncate_lines ? Qt : Qnil;
+
/* Insert new message at BEG. */
TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
window_height_changed_p = display_echo_area (w);
w->must_be_updated_p = 1;
+ /* Update the display, unless called from redisplay_internal. */
if (update_frame_p)
{
- /* Not called from redisplay_internal. If we changed
- window configuration, we must redisplay thoroughly.
- Otherwise, we can do with updating what we displayed
- above. */
+ int n = 0;
+
+ /* If the display update has been interrupted by pending
+ input, update mode lines in the frame. Due to the
+ pending input, it might have been that redisplay hasn't
+ been called, so that mode lines above the echo area are
+ garbaged. This looks odd, so we prevent it here. */
+ if (!display_completed)
+ n = redisplay_mode_lines (FRAME_ROOT_WINDOW (f), 0);
+
if (window_height_changed_p)
{
- ++windows_or_buffers_changed;
- ++update_mode_lines;
+ /* Must update other windows. */
+ windows_or_buffers_changed = 1;
redisplay_internal (0);
}
- else if (FRAME_WINDOW_P (f))
+ else if (FRAME_WINDOW_P (f) && n == 0)
{
+ /* Window configuration is the same as before.
+ Can do with a display update of the echo area,
+ unless we displayed some mode lines. */
update_single_window (w, 1);
rif->flush_display (f);
}
int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
- int margin, relief;
+ int margin, relief, idx;
extern Lisp_Object QCrelief, QCmargin, QCalgorithm, Qimage;
extern Lisp_Object Qlaplace;
image = PROP (TOOL_BAR_ITEM_IMAGES);
if (VECTORP (image))
{
- enum tool_bar_item_image idx;
-
if (enabled_p)
idx = (selected_p
? TOOL_BAR_IMAGE_ENABLED_SELECTED
? TOOL_BAR_IMAGE_DISABLED_SELECTED
: TOOL_BAR_IMAGE_DISABLED_DESELECTED);
- xassert (XVECTOR (image)->size >= idx);
- image = XVECTOR (image)->contents[idx];
+ xassert (ASIZE (image) >= idx);
+ image = AREF (image, idx);
}
+ else
+ idx = -1;
/* Ignore invalid image specifications. */
if (!valid_image_p (image))
if (margin)
plist = Fplist_put (plist, QCmargin, make_number (margin));
- /* If button is not enabled, make the image appear disabled by
+ /* If button is not enabled, and we don't have special images
+ for the disabled state, make the image appear disabled by
applying an appropriate algorithm to it. */
- if (!enabled_p)
- plist = Fplist_put (plist, QCalgorithm, Qlaplace);
+ if (!enabled_p && idx < 0)
+ plist = Fplist_put (plist, QCalgorithm, Qdisabled);
/* Put a `display' text property on the string for the image to
display. Put a `menu-item' property on the string that gives
++redisplaying_p;
retry:
-
+ pause = 0;
reconsider_clip_changes (w, current_buffer);
/* If new fonts have been loaded that make a glyph matrix adjustment
clear_garbaged_frames ();
}
}
- else if (w == XWINDOW (minibuf_window)
+ else if (EQ (selected_window, minibuf_window)
&& (current_buffer->clip_changed
|| XFASTINT (w->last_modified) < MODIFF
|| XFASTINT (w->last_overlay_modified) < OVERLAY_MODIFF)
then we can't just move the cursor. */
else if (! (!NILP (Vtransient_mark_mode)
&& !NILP (current_buffer->mark_active))
- && (w == XWINDOW (current_buffer->last_selected_window)
+ && (EQ (selected_window, current_buffer->last_selected_window)
|| highlight_nonselected_windows)
&& NILP (w->region_showing)
&& NILP (Vshow_trailing_whitespace)
++clear_face_cache_count;
- /* Build desired matrices. If consider_all_windows_p is non-zero,
- do it for all windows on all frames. Otherwise do it for
- selected_window, only. */
+ /* Build desired matrices, and update the display. If
+ consider_all_windows_p is non-zero, do it for all windows on all
+ frames. Otherwise do it for selected_window, only. */
if (consider_all_windows_p)
{
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
+
if (FRAME_WINDOW_P (f) || f == sf)
{
/* Mark all the scroll bars to be removed; we'll redeem
nuked should now go away. */
if (judge_scroll_bars_hook)
(*judge_scroll_bars_hook) (f);
+
+ /* If fonts changed, display again. */
+ if (fonts_changed_p)
+ goto retry;
+
+ if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
+ {
+ /* See if we have to hscroll. */
+ if (hscroll_windows (f->root_window))
+ goto retry;
+
+ /* Prevent various kinds of signals during display
+ update. stdio is not robust about handling
+ signals, which can cause an apparent I/O
+ error. */
+ if (interrupt_input)
+ unrequest_sigio ();
+ stop_polling ();
+
+ /* Update the display. */
+ set_window_update_flags (XWINDOW (f->root_window), 1);
+ pause |= update_frame (f, 0, 0);
+ if (pause)
+ break;
+
+ mark_window_display_accurate (f->root_window, 1);
+ if (frame_up_to_date_hook)
+ frame_up_to_date_hook (f);
+ }
}
}
}
- else if (FRAME_VISIBLE_P (sf)
- && !FRAME_OBSCURED_P (sf))
- redisplay_window (selected_window, 1);
+ else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
+ {
+ Lisp_Object mini_window;
+ struct frame *mini_frame;
+ redisplay_window (selected_window, 1);
- /* Compare desired and current matrices, perform output. */
-
-update:
+ /* Compare desired and current matrices, perform output. */
+ update:
- /* If fonts changed, display again. */
- if (fonts_changed_p)
- goto retry;
-
- /* Prevent various kinds of signals during display update.
- stdio is not robust about handling signals,
- which can cause an apparent I/O error. */
- if (interrupt_input)
- unrequest_sigio ();
- stop_polling ();
-
- if (consider_all_windows_p)
- {
- Lisp_Object tail;
- struct frame *f;
- int hscrolled_p;
-
- pause = 0;
- hscrolled_p = 0;
-
- /* See if we have to hscroll. */
- for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
- if (FRAMEP (XCAR (tail)))
- {
- f = XFRAME (XCAR (tail));
-
- if ((FRAME_WINDOW_P (f)
- || f == sf)
- && FRAME_VISIBLE_P (f)
- && !FRAME_OBSCURED_P (f)
- && hscroll_windows (f->root_window))
- hscrolled_p = 1;
- }
-
- if (hscrolled_p)
+ /* If fonts changed, display again. */
+ if (fonts_changed_p)
goto retry;
- for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
- {
- if (!FRAMEP (XCAR (tail)))
- continue;
-
- f = XFRAME (XCAR (tail));
+ /* Prevent various kinds of signals during display update.
+ stdio is not robust about handling signals,
+ which can cause an apparent I/O error. */
+ if (interrupt_input)
+ unrequest_sigio ();
+ stop_polling ();
- if ((FRAME_WINDOW_P (f) || f == sf)
- && FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
- {
- /* Mark all windows as to be updated. */
- set_window_update_flags (XWINDOW (f->root_window), 1);
- pause |= update_frame (f, 0, 0);
- if (!pause)
- {
- mark_window_display_accurate (f->root_window, 1);
- if (frame_up_to_date_hook != 0)
- (*frame_up_to_date_hook) (f);
- }
- }
- }
- }
- else
- {
- if (FRAME_VISIBLE_P (sf)
- && !FRAME_OBSCURED_P (sf))
+ if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
{
if (hscroll_windows (selected_window))
goto retry;
XWINDOW (selected_window)->must_be_updated_p = 1;
pause = update_frame (sf, 0, 0);
}
- else
- pause = 0;
/* We may have called echo_area_display at the top of this
function. If the echo area is on another frame, that may
have put text on a frame other than the selected one, so the
above call to update_frame would not have caught it. Catch
it here. */
- {
- Lisp_Object mini_window;
- struct frame *mini_frame;
-
- mini_window = FRAME_MINIBUF_WINDOW (sf);
- mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
+ mini_window = FRAME_MINIBUF_WINDOW (sf);
+ mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
- if (mini_frame != sf && FRAME_WINDOW_P (mini_frame))
- {
- XWINDOW (mini_window)->must_be_updated_p = 1;
- pause |= update_frame (mini_frame, 0, 0);
- if (!pause && hscroll_windows (mini_window))
- goto retry;
- }
- }
+ if (mini_frame != sf && FRAME_WINDOW_P (mini_frame))
+ {
+ XWINDOW (mini_window)->must_be_updated_p = 1;
+ pause |= update_frame (mini_frame, 0, 0);
+ if (!pause && hscroll_windows (mini_window))
+ goto retry;
+ }
}
/* If display was paused because of pending input, make sure we do a
/* 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)
- && (w == XWINDOW (current_buffer->last_selected_window)
+ && (EQ (selected_window,
+ current_buffer->last_selected_window)
|| highlight_nonselected_windows)
&& !NILP (XBUFFER (w->buffer)->mark_active)
? Fmarker_position (XBUFFER (w->buffer)->mark)
{
struct glyph_matrix *matrix;
struct glyph_row *row;
- int header_line_height;
+ int window_height, header_line_height;
/* It's not always possible to find the cursor, e.g, when a window
is full of overlay strings. Don't do anything in that case. */
matrix = w->desired_matrix;
row = MATRIX_ROW (matrix, w->cursor.vpos);
- if (MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (w, row)
- /* The row may be partially visible at the top because we
- already have chosen a vscroll to align the bottom of the
- row with the bottom of the window. This happens for rows
- taller than the window. */
- && row->y + row->height < window_box_height (w))
- {
- int dy = row->height - row->visible_height;
+ /* If the cursor row is not partially visible, there's nothing
+ to do. */
+ if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
+ return;
+
+ /* If the row the cursor is in is taller than the window's height,
+ it's not clear what to do, so do nothing. */
+ window_height = window_box_height (w);
+ if (row->height >= window_height)
+ return;
+
+ if (MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (w, row))
+ {
+ int dy = row->height - row->visible_height;
w->vscroll = 0;
w->cursor.y += dy;
shift_glyph_matrix (w, matrix, 0, matrix->nrows, dy);
}
- else if (MATRIX_ROW_PARTIALLY_VISIBLE_AT_BOTTOM_P (w, row)
- /* The row may be partially visible at the bottom because
- we chose a vscroll to align the row's top with the
- window's top. This happens for rows taller than the
- window. */
- && row->y > WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w))
+ else /* MATRIX_ROW_PARTIALLY_VISIBLE_AT_BOTTOM_P (w, row)) */
{
int dy = - (row->height - row->visible_height);
w->vscroll = dy;
w->cursor.y += dy;
shift_glyph_matrix (w, matrix, 0, matrix->nrows, dy);
}
-
+
/* When we change the cursor y-position of the selected window,
change this_line_y as well so that the display optimization for
the cursor line of the selected window in redisplay_internal uses
/* Point is in the scroll margin at the bottom of the window, or
below. Compute a new window start that makes point visible. */
-
+
/* Compute the distance from the scroll margin to PT.
Give up if the distance is greater than scroll_max. */
start_display (&it, w, scroll_margin_pos);
? it.max_ascent + it.max_descent
: last_height);
dy = it.current_y + line_height - y0;
+
if (dy > scroll_max)
return 0;
}
+/* Try cursor movement in case text has not changes in window WINDOW,
+ with window start STARTP. Value is
+
+ 1 if successful
+
+ 0 if this method cannot be used
+
+ -1 if we know we have to scroll the display. *SCROLL_STEP is
+ set to 1, under certain circumstances, if we want to scroll as
+ if scroll-step were set to 1. See the code. */
+
+static int
+try_cursor_movement (window, startp, scroll_step)
+ Lisp_Object window;
+ struct text_pos startp;
+ int *scroll_step;
+{
+ struct window *w = XWINDOW (window);
+ struct frame *f = XFRAME (w->frame);
+ int rc = 0;
+
+ /* Handle case where text has not changed, only point, and it has
+ not moved off the frame. */
+ if (/* Point may be in this window. */
+ PT >= CHARPOS (startp)
+ /* If we don't check this, we are called to move the cursor in a
+ horizontally split window with a current matrix that doesn't
+ fit the display. */
+ && !windows_or_buffers_changed
+ /* Selective display hasn't changed. */
+ && !current_buffer->clip_changed
+ /* If force-mode-line-update was called, really redisplay;
+ that's how redisplay is forced after e.g. changing
+ buffer-invisibility-spec. */
+ && NILP (w->update_mode_line)
+ /* Can't use this case if highlighting a region. When a
+ region exists, cursor movement has to do more than just
+ set the cursor. */
+ && !(!NILP (Vtransient_mark_mode)
+ && !NILP (current_buffer->mark_active))
+ && NILP (w->region_showing)
+ && NILP (Vshow_trailing_whitespace)
+ /* Right after splitting windows, last_point may be nil. */
+ && INTEGERP (w->last_point)
+ /* This code is not used for mini-buffer for the sake of the case
+ of redisplaying to replace an echo area message; since in
+ that case the mini-buffer contents per se are usually
+ unchanged. This code is of no real use in the mini-buffer
+ since the handling of this_line_start_pos, etc., in redisplay
+ handles the same cases. */
+ && !EQ (window, minibuf_window)
+ /* When splitting windows or for new windows, it happens that
+ redisplay is called with a nil window_end_vpos or one being
+ larger than the window. This should really be fixed in
+ window.c. I don't have this on my list, now, so we do
+ approximately the same as the old redisplay code. --gerd. */
+ && INTEGERP (w->window_end_vpos)
+ && XFASTINT (w->window_end_vpos) < w->current_matrix->nrows
+ && (FRAME_WINDOW_P (f)
+ || !MARKERP (Voverlay_arrow_position)
+ || current_buffer != XMARKER (Voverlay_arrow_position)->buffer))
+ {
+ int this_scroll_margin;
+ struct glyph_row *row;
+
+#if GLYPH_DEBUG
+ debug_method_add (w, "cursor movement");
+#endif
+
+ /* Scroll if point within this distance from the top or bottom
+ of the window. This is a pixel value. */
+ this_scroll_margin = max (0, scroll_margin);
+ this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
+ this_scroll_margin *= CANON_Y_UNIT (f);
+
+ /* Start with the row the cursor was displayed during the last
+ not paused redisplay. Give up if that row is not valid. */
+ if (w->last_cursor.vpos < 0
+ || w->last_cursor.vpos >= w->current_matrix->nrows)
+ rc = -1;
+ else
+ {
+ row = MATRIX_ROW (w->current_matrix, w->last_cursor.vpos);
+ if (row->mode_line_p)
+ ++row;
+ if (!row->enabled_p)
+ rc = -1;
+ }
+
+ if (rc == 0)
+ {
+ int scroll_p = 0;
+
+ if (PT > XFASTINT (w->last_point))
+ {
+ /* Point has moved forward. */
+ int last_y = window_text_bottom_y (w) - this_scroll_margin;
+
+ while (MATRIX_ROW_END_CHARPOS (row) < PT
+ && MATRIX_ROW_BOTTOM_Y (row) < last_y)
+ {
+ xassert (row->enabled_p);
+ ++row;
+ }
+
+ /* The end position of a row equals the start position
+ of the next row. If PT is there, we would rather
+ display it in the next line. Exceptions are when the
+ row ends in the middle of a character, or ends in
+ ZV. */
+ if (MATRIX_ROW_BOTTOM_Y (row) < last_y
+ && MATRIX_ROW_END_CHARPOS (row) == PT
+ && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)
+ && !row->ends_at_zv_p)
+ {
+ xassert (row->enabled_p);
+ ++row;
+ }
+
+ /* If within the scroll margin, scroll. Note that
+ MATRIX_ROW_BOTTOM_Y gives the pixel position at which
+ the next line would be drawn, and that
+ this_scroll_margin can be zero. */
+ if (MATRIX_ROW_BOTTOM_Y (row) > last_y
+ || PT > MATRIX_ROW_END_CHARPOS (row)
+ /* Line is completely visible last line in window
+ and PT is to be set in the next line. */
+ || (MATRIX_ROW_BOTTOM_Y (row) == last_y
+ && PT == MATRIX_ROW_END_CHARPOS (row)
+ && !row->ends_at_zv_p
+ && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))
+ scroll_p = 1;
+ }
+ else if (PT < XFASTINT (w->last_point))
+ {
+ /* Cursor has to be moved backward. Note that PT >=
+ CHARPOS (startp) because of the outer
+ if-statement. */
+ while (!row->mode_line_p
+ && (MATRIX_ROW_START_CHARPOS (row) > PT
+ || (MATRIX_ROW_START_CHARPOS (row) == PT
+ && MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P (row)))
+ && (row->y > this_scroll_margin
+ || CHARPOS (startp) == BEGV))
+ {
+ xassert (row->enabled_p);
+ --row;
+ }
+
+ /* Consider the following case: Window starts at BEGV,
+ there is invisible, intangible text at BEGV, so that
+ display starts at some point START > BEGV. It can
+ happen that we are called with PT somewhere between
+ BEGV and START. Try to handle that case. */
+ if (row < w->current_matrix->rows
+ || row->mode_line_p)
+ {
+ row = w->current_matrix->rows;
+ if (row->mode_line_p)
+ ++row;
+ }
+
+ /* Due to newlines in overlay strings, we may have to
+ skip forward over overlay strings. */
+ while (MATRIX_ROW_END_CHARPOS (row) == PT
+ && MATRIX_ROW_ENDS_IN_OVERLAY_STRING_P (row)
+ && !row->ends_at_zv_p)
+ ++row;
+
+ /* If within the scroll margin, scroll. */
+ if (row->y < this_scroll_margin
+ && CHARPOS (startp) != BEGV)
+ scroll_p = 1;
+ }
+
+ if (PT < MATRIX_ROW_START_CHARPOS (row)
+ || PT > MATRIX_ROW_END_CHARPOS (row))
+ {
+ /* if PT is not in the glyph row, give up. */
+ rc = -1;
+ }
+ else if (MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
+ {
+ /* If we end up in a partially visible line, let's make it
+ fully visible, except when it's taller than the window,
+ in which case we can't do much about it. */
+ if (row->height > window_box_height (w))
+ {
+ *scroll_step = 1;
+ rc = -1;
+ }
+ else
+ {
+ set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+ try_window (window, startp);
+ make_cursor_line_fully_visible (w);
+ rc = 1;
+ }
+ }
+ else if (scroll_p)
+ rc = -1;
+ else
+ {
+ set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+ rc = 1;
+ }
+ }
+ }
+
+ return rc;
+}
+
+
/* Redisplay leaf window WINDOW. JUST_THIS_ONE_P non-zero means only
selected_window is redisplayed. */
int current_matrix_up_to_date_p = 0;
int temp_scroll_step = 0;
int count = specpdl_ptr - specpdl;
+ int rc;
SET_TEXT_POS (lpoint, PT, PT_BYTE);
opoint = lpoint;
&& CHARPOS (startp) <= ZV)
{
w->optional_new_start = Qnil;
- /* This takes a mini-buffer prompt into account. */
start_display (&it, w, startp);
move_it_to (&it, PT, 0, it.last_visible_y, -1,
MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
if (w->cursor.vpos < 0 && !w->frozen_window_start_p)
{
- /* If point does not appear, or on a line that is not fully
- visible, move point so it does appear. The desired
- matrix has been built above, so we can use it. */
- int height = window_box_height (w) / 2;
- struct glyph_row *row = MATRIX_ROW (w->desired_matrix, 0);
-
- while (row->y < height)
+ /* If point does not appear, try to move point so it does
+ appear. The desired matrix has been built above, so we
+ can use it here. */
+ int window_height;
+ struct glyph_row *row;
+
+ window_height = window_box_height (w) / 2;
+ row = MATRIX_FIRST_TEXT_ROW (w->desired_matrix);
+ while (MATRIX_ROW_BOTTOM_Y (row) < window_height)
++row;
TEMP_SET_PT_BOTH (MATRIX_ROW_START_CHARPOS (row),
/* Handle case where text has not changed, only point, and it has
not moved off the frame. */
if (current_matrix_up_to_date_p
- /* Point may be in this window. */
- && PT >= CHARPOS (startp)
- /* If we don't check this, we are called to move the cursor in a
- horizontally split window with a current matrix that doesn't
- fit the display. */
- && !windows_or_buffers_changed
- /* Selective display hasn't changed. */
- && !current_buffer->clip_changed
- /* If force-mode-line-update was called, really redisplay;
- that's how redisplay is forced after e.g. changing
- buffer-invisibility-spec. */
- && NILP (w->update_mode_line)
- /* Can't use this case if highlighting a region. When a
- region exists, cursor movement has to do more than just
- set the cursor. */
- && !(!NILP (Vtransient_mark_mode)
- && !NILP (current_buffer->mark_active))
- && NILP (w->region_showing)
- && NILP (Vshow_trailing_whitespace)
- /* Right after splitting windows, last_point may be nil. */
- && INTEGERP (w->last_point)
- /* This code is not used for mini-buffer for the sake of the case
- of redisplaying to replace an echo area message; since in
- that case the mini-buffer contents per se are usually
- unchanged. This code is of no real use in the mini-buffer
- since the handling of this_line_start_pos, etc., in redisplay
- handles the same cases. */
- && !EQ (window, minibuf_window)
- /* When splitting windows or for new windows, it happens that
- redisplay is called with a nil window_end_vpos or one being
- larger than the window. This should really be fixed in
- window.c. I don't have this on my list, now, so we do
- approximately the same as the old redisplay code. --gerd. */
- && INTEGERP (w->window_end_vpos)
- && XFASTINT (w->window_end_vpos) < w->current_matrix->nrows
- && (FRAME_WINDOW_P (f)
- || !MARKERP (Voverlay_arrow_position)
- || current_buffer != XMARKER (Voverlay_arrow_position)->buffer))
+ && (rc = try_cursor_movement (window, startp, &temp_scroll_step),
+ rc != 0))
{
- int this_scroll_margin;
- struct glyph_row *row;
- int scroll_p;
-
-#if GLYPH_DEBUG
- debug_method_add (w, "cursor movement");
-#endif
-
- /* Scroll if point within this distance from the top or bottom
- of the window. This is a pixel value. */
- this_scroll_margin = max (0, scroll_margin);
- this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
- this_scroll_margin *= CANON_Y_UNIT (f);
-
- /* Start with the row the cursor was displayed during the last
- not paused redisplay. Give up if that row is not valid. */
- if (w->last_cursor.vpos >= w->current_matrix->nrows)
+ if (rc == -1)
goto try_to_scroll;
- row = MATRIX_ROW (w->current_matrix, w->last_cursor.vpos);
- if (row->mode_line_p)
- ++row;
- if (!row->enabled_p)
- goto try_to_scroll;
-
- scroll_p = 0;
- if (PT > XFASTINT (w->last_point))
- {
- /* Point has moved forward. */
- int last_y = window_text_bottom_y (w) - this_scroll_margin;
-
- while (MATRIX_ROW_END_CHARPOS (row) < PT
- && MATRIX_ROW_BOTTOM_Y (row) < last_y)
- {
- xassert (row->enabled_p);
- ++row;
- }
-
- /* The end position of a row equals the start position of
- the next row. If PT is there, we would rather display it
- in the next line. Exceptions are when the row ends in
- the middle of a character, or ends in ZV. */
- if (MATRIX_ROW_BOTTOM_Y (row) < last_y
- && MATRIX_ROW_END_CHARPOS (row) == PT
- && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)
- && !row->ends_at_zv_p)
- {
- xassert (row->enabled_p);
- ++row;
- }
-
- /* If within the scroll margin, scroll. Note that
- MATRIX_ROW_BOTTOM_Y gives the pixel position at which the
- next line would be drawn, and that this_scroll_margin can
- be zero. */
- if (MATRIX_ROW_BOTTOM_Y (row) > last_y
- || PT > MATRIX_ROW_END_CHARPOS (row)
- /* Line is completely visible last line in window and PT
- is to be set in the next line. */
- || (MATRIX_ROW_BOTTOM_Y (row) == last_y
- && PT == MATRIX_ROW_END_CHARPOS (row)
- && !row->ends_at_zv_p
- && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))
- scroll_p = 1;
- }
- else if (PT < XFASTINT (w->last_point))
- {
- /* Cursor has to be moved backward. Note that PT >=
- CHARPOS (startp) because of the outer if-statement. */
- while (!row->mode_line_p
- && (MATRIX_ROW_START_CHARPOS (row) > PT
- || (MATRIX_ROW_START_CHARPOS (row) == PT
- && MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P (row)))
- && (row->y > this_scroll_margin
- || CHARPOS (startp) == BEGV))
- {
- xassert (row->enabled_p);
- --row;
- }
-
- /* Consider the following case: Window starts at BEGV, there
- is invisible, intangible text at BEGV, so that display
- starts at some point START > BEGV. It can happen that
- we are called with PT somewhere between BEGV and START.
- Try to handle that case. */
- if (row < w->current_matrix->rows
- || row->mode_line_p)
- {
- row = w->current_matrix->rows;
- if (row->mode_line_p)
- ++row;
- }
-
- /* Due to newlines in overlay strings, we may have to skip
- forward over overlay strings. */
- while (MATRIX_ROW_END_CHARPOS (row) == PT
- && MATRIX_ROW_ENDS_IN_OVERLAY_STRING_P (row)
- && !row->ends_at_zv_p)
- ++row;
-
- /* If within the scroll margin, scroll. */
- if (row->y < this_scroll_margin
- && CHARPOS (startp) != BEGV)
- scroll_p = 1;
- }
-
- /* if PT is not in the glyph row, give up. */
- if (PT < MATRIX_ROW_START_CHARPOS (row)
- || PT > MATRIX_ROW_END_CHARPOS (row))
- goto try_to_scroll;
-
- /* If we end up in a partially visible line, let's make it fully
- visible. This can be done most easily by using the existing
- scrolling code. */
- if (MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
- {
- temp_scroll_step = 1;
- goto try_to_scroll;
- }
- else if (scroll_p)
- goto try_to_scroll;
-
- set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
- goto done;
+ else
+ goto done;
}
-
/* 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)
&& (tem = try_window_id (w)) != 0)
{
#if GLYPH_DEBUG
- debug_method_add (w, "try_window_id");
+ debug_method_add (w, "try_window_id %d", tem);
#endif
if (fonts_changed_p)
goto restore_buffers;
if (tem > 0)
goto done;
+
/* Otherwise try_window_id has returned -1 which means that we
don't want the alternative below this comment to execute. */
}
struct glyph_row *last_reused_text_row;
struct glyph_row *start_row;
int start_vpos, min_y, max_y;
-
- /* Right now this function doesn't handle terminal frames. */
- if (!FRAME_WINDOW_P (f))
+
+ if (/* This function doesn't handle terminal frames. */
+ !FRAME_WINDOW_P (f)
+ /* Don't try to reuse the display if windows have been split
+ or such. */
+ || windows_or_buffers_changed)
return 0;
/* Can't do this if region may have changed. */
/* Display up to a row that can be reused. The variable
last_text_row is set to the last row displayed that displays
- text. */
+ text. Note that it.vpos == 0 if or if not there is a
+ header-line; it's not the same as the MATRIX_ROW_VPOS! */
start_display (&it, w, new_start);
first_row_y = it.current_y;
w->cursor.vpos = -1;
last_text_row = last_reused_text_row = NULL;
+
while (it.current_y < it.last_visible_y
&& IT_CHARPOS (it) < CHARPOS (start)
&& !fonts_changed_p)
have at least one reusable row. */
if (it.current_y < it.last_visible_y)
{
+ /* IT.vpos always starts from 0; it counts text lines. */
nrows_scrolled = it.vpos;
/* Find PT if not already found in the lines displayed. */
run.current_y = first_row_y;
run.desired_y = it.current_y;
run.height = it.last_visible_y - it.current_y;
- if (run.height > 0
- && run.current_y != run.desired_y)
+
+ if (run.height > 0 && run.current_y != run.desired_y)
{
update_begin (f);
rif->update_window_begin_hook (w);
+ rif->clear_mouse_face (w);
rif->scroll_run_hook (w, &run);
- rif->update_window_end_hook (w, 0);
+ rif->update_window_end_hook (w, 0, 0);
update_end (f);
}
/* Disable lines not reused. */
for (i = 0; i < it.vpos; ++i)
- MATRIX_ROW (w->current_matrix, i)->enabled_p = 0;
+ (start_row + i)->enabled_p = 0;
/* Re-compute Y positions. */
- row = MATRIX_FIRST_TEXT_ROW (w->current_matrix) + nrows_scrolled;
min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
max_y = it.last_visible_y;
- while (row < bottom_row)
+ for (row = start_row + nrows_scrolled;
+ row < bottom_row;
+ ++row)
{
row->y = it.current_y;
row->visible_height = row->height;
it.current_y += row->height;
- ++it.vpos;
if (MATRIX_ROW_DISPLAYS_TEXT_P (row))
last_reused_text_row = row;
if (MATRIX_ROW_BOTTOM_Y (row) >= it.last_visible_y)
break;
- ++row;
}
}
/* Find the row starting at new_start, if there is one. Don't
reuse a partially visible line at the end. */
- first_reusable_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+ first_reusable_row = start_row;
while (first_reusable_row->enabled_p
&& MATRIX_ROW_BOTTOM_Y (first_reusable_row) < yb
&& (MATRIX_ROW_START_CHARPOS (first_reusable_row)
/* Start displaying at the start of first_row_to_display. */
xassert (first_row_to_display->y < yb);
init_to_row_start (&it, w, first_row_to_display);
- nrows_scrolled = MATRIX_ROW_VPOS (first_reusable_row, w->current_matrix);
+ nrows_scrolled = (MATRIX_ROW_VPOS (first_reusable_row, w->current_matrix)
+ - start_vpos);
it.vpos = (MATRIX_ROW_VPOS (first_row_to_display, w->current_matrix)
- nrows_scrolled);
- it.current_y = first_row_to_display->y - first_reusable_row->y;
+ it.current_y = (first_row_to_display->y - first_reusable_row->y
+ + WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w));
/* Display lines beginning with first_row_to_display in the
desired matrix. Set last_text_row to the last row displayed
run.current_y = first_reusable_row->y;
run.desired_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
run.height = it.last_visible_y - run.current_y;
+ dy = run.current_y - run.desired_y;
+
if (run.height)
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
update_begin (f);
rif->update_window_begin_hook (w);
+ rif->clear_mouse_face (w);
rif->scroll_run_hook (w, &run);
- rif->update_window_end_hook (w, 0);
+ rif->update_window_end_hook (w, 0, 0);
update_end (f);
}
/* Adjust Y positions of reused rows. */
bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
- row = first_reusable_row;
- dy = first_reusable_row->y;
min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
max_y = it.last_visible_y;
- while (row < first_row_to_display)
+ for (row = first_reusable_row; row < first_row_to_display; ++row)
{
row->y -= dy;
if (row->y < min_y)
= row->height - (row->y + row->height - max_y);
else
row->visible_height = row->height;
- ++row;
}
/* Disable rows not reused. */
= make_number (Z - MATRIX_ROW_END_CHARPOS (row));
w->window_end_bytepos
= Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
- return 1;
+
+ row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+ row = row_containing_pos (w, PT, row, NULL);
+ set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+ return 2;
}
/* Check that window start agrees with the start of the first glyph
row = row_containing_pos (w, PT,
MATRIX_FIRST_TEXT_ROW (w->current_matrix),
last_unchanged_at_beg_row + 1);
- xassert (row && row <= last_unchanged_at_beg_row);
- set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+ if (row)
+ set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
}
/* Start from first_unchanged_at_end_row looking for PT. */
if (FRAME_WINDOW_P (f))
{
rif->update_window_begin_hook (w);
+ rif->clear_mouse_face (w);
rif->scroll_run_hook (w, &run);
- rif->update_window_end_hook (w, 0);
+ rif->update_window_end_hook (w, 0, 0);
}
else
{
/* Record that display has not been completed. */
w->window_end_valid = Qnil;
w->desired_matrix->no_scrolling_p = 1;
- return 1;
+ return 3;
}
/* Dump the contents of glyph matrix MATRIX on stderr. If
WITH_GLYPHS_P is non-zero, dump glyph contents as well. */
-void
+static void
dump_glyph_matrix (matrix, with_glyphs_p)
struct glyph_matrix *matrix;
int with_glyphs_p;
row = MATRIX_ROW (matrix, vpos);
- fprintf (stderr, "Row Start End Used oEI><O\\CTZFes X Y W\n");
- fprintf (stderr, "=============================================\n");
+ fprintf (stderr, "Row Start End Used oEI><O\\CTZFes X Y W H V A P\n");
+ fprintf (stderr, "=======================================================================\n");
- fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d %4d %4d %4d\n",
+ fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d%1.1d%1.1d\
+%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d %4d %4d %4d %4d %4d %4d %4d\n",
row - matrix->rows,
MATRIX_ROW_START_CHARPOS (row),
MATRIX_ROW_END_CHARPOS (row),
row->starts_in_middle_of_char_p,
row->x,
row->y,
- row->pixel_width);
+ row->pixel_width,
+ row->height,
+ row->visible_height,
+ row->ascent,
+ row->phys_ascent);
fprintf (stderr, "%9d %5d\n", row->start.overlay_string_index,
row->end.overlay_string_index);
fprintf (stderr, "%9d %5d\n",
if (glyph < glyph_end)
{
- fprintf (stderr, " Glyph Type Pos W Code C Face LR\n");
+ fprintf (stderr, " Glyph Type Pos O W Code C Face LR\n");
prev_had_glyphs_p = 1;
}
else
if (glyph->type == CHAR_GLYPH)
{
fprintf (stderr,
- " %5d %4c %6d %3d 0x%05x %c %4d %1.1d%1.1d\n",
+ " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
glyph - row->glyphs[TEXT_AREA],
'C',
glyph->charpos,
+ (BUFFERP (glyph->object)
+ ? 'B'
+ : (STRINGP (glyph->object)
+ ? 'S'
+ : '-')),
glyph->pixel_width,
glyph->u.ch,
(glyph->u.ch < 0x80 && glyph->u.ch >= ' '
else if (glyph->type == STRETCH_GLYPH)
{
fprintf (stderr,
- " %5d %4c %6d %3d 0x%05x %c %4d %1.1d%1.1d\n",
+ " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
glyph - row->glyphs[TEXT_AREA],
'S',
glyph->charpos,
+ (BUFFERP (glyph->object)
+ ? 'B'
+ : (STRINGP (glyph->object)
+ ? 'S'
+ : '-')),
glyph->pixel_width,
0,
'.',
else if (glyph->type == IMAGE_GLYPH)
{
fprintf (stderr,
- " %5d %4c %6d %3d 0x%05x %c %4d %1.1d%1.1d\n",
+ " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
glyph - row->glyphs[TEXT_AREA],
'I',
glyph->charpos,
+ (BUFFERP (glyph->object)
+ ? 'B'
+ : (STRINGP (glyph->object)
+ ? 'S'
+ : '-')),
glyph->pixel_width,
glyph->u.img_id,
'.',
/* If first line's physical ascent is larger than its logical
ascent, use the physical ascent, and make the row taller.
This makes accented characters fully visible. */
- if (row == it->w->desired_matrix->rows
+ if (row == MATRIX_FIRST_TEXT_ROW (it->w->desired_matrix)
&& row->phys_ascent > row->ascent)
{
row->height += row->phys_ascent - row->ascent;
{
int n_glyphs_before, hpos_before, x_before;
int x, i, nglyphs;
- int ascent, descent, phys_ascent, phys_descent;
-
+ int ascent = 0, descent = 0, phys_ascent = 0, phys_descent = 0;
+
/* Retrieve the next thing to display. Value is zero if end of
buffer reached. */
if (!get_next_display_element (it))
Mode Line
***********************************************************************/
-/* Display the mode and/or top line of window W. */
+/* Redisplay mode lines in the window tree whose root is WINDOW. If
+ FORCE is non-zero, redisplay mode lines unconditionally.
+ Otherwise, redisplay only mode lines that are garbaged. Value is
+ the number of windows whose mode lines were redisplayed. */
-static void
+static int
+redisplay_mode_lines (window, force)
+ Lisp_Object window;
+ int force;
+{
+ int nwindows = 0;
+
+ while (!NILP (window))
+ {
+ struct window *w = XWINDOW (window);
+
+ if (WINDOWP (w->hchild))
+ nwindows += redisplay_mode_lines (w->hchild, force);
+ else if (WINDOWP (w->vchild))
+ nwindows += redisplay_mode_lines (w->vchild, force);
+ else if (force
+ || FRAME_GARBAGED_P (XFRAME (w->frame))
+ || !MATRIX_MODE_LINE_ROW (w->current_matrix)->enabled_p)
+ {
+ Lisp_Object old_selected_frame;
+ struct text_pos lpoint;
+ struct buffer *old = current_buffer;
+
+ /* Set the window's buffer for the mode line display. */
+ SET_TEXT_POS (lpoint, PT, PT_BYTE);
+ set_buffer_internal_1 (XBUFFER (w->buffer));
+
+ /* Point refers normally to the selected window. For any
+ other window, set up appropriate value. */
+ if (!EQ (window, selected_window))
+ {
+ struct text_pos pt;
+
+ SET_TEXT_POS_FROM_MARKER (pt, w->pointm);
+ if (CHARPOS (pt) < BEGV)
+ TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
+ else if (CHARPOS (pt) > (ZV - 1))
+ TEMP_SET_PT_BOTH (ZV, ZV_BYTE);
+ else
+ TEMP_SET_PT_BOTH (CHARPOS (pt), BYTEPOS (pt));
+ }
+
+ /* Temporarily set up the selected frame. */
+ old_selected_frame = selected_frame;
+ selected_frame = w->frame;
+
+ /* Display mode lines. */
+ clear_glyph_matrix (w->desired_matrix);
+ if (display_mode_lines (w))
+ {
+ ++nwindows;
+ w->must_be_updated_p = 1;
+ }
+
+ /* Restore old settings. */
+ selected_frame = old_selected_frame;
+ set_buffer_internal_1 (old);
+ TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
+ }
+
+ window = w->next;
+ }
+
+ return nwindows;
+}
+
+
+/* Display the mode and/or top line of window W. Value is the number
+ of mode lines displayed. */
+
+static int
display_mode_lines (w)
struct window *w;
{
+ int n = 0;
+
/* These will be set while the mode line specs are processed. */
line_number_displayed = 0;
w->column_number_displayed = Qnil;
if (WINDOW_WANTS_MODELINE_P (w))
- display_mode_line (w, MODE_LINE_FACE_ID,
- current_buffer->mode_line_format);
+ {
+ display_mode_line (w, MODE_LINE_FACE_ID,
+ current_buffer->mode_line_format);
+ ++n;
+ }
if (WINDOW_WANTS_HEADER_LINE_P (w))
- display_mode_line (w, HEADER_LINE_FACE_ID,
- current_buffer->header_line_format);
+ {
+ display_mode_line (w, HEADER_LINE_FACE_ID,
+ current_buffer->header_line_format);
+ ++n;
+ }
+
+ return n;
}
Lisp_Object eoltype;
val = Fget (coding_system, Qcoding_system);
+ eoltype = Qnil;
if (!VECTORP (val)) /* Not yet decided. */
{
w->base_line_pos = Qnil;
/* If the buffer is very big, don't waste time. */
- if (!INTEGERP (Vline_number_display_limit)
+ if (INTEGERP (Vline_number_display_limit)
&& BUF_ZV (b) - BUF_BEGV (b) > XINT (Vline_number_display_limit))
{
w->base_line_pos = Qnil;
while (pad-- > 0)
*p++ = ' ';
*p++ = '?';
- *p = '?';
+ *p++ = '?';
+ *p = '\0';
return decode_mode_spec_buf;
}
}
Lisp_Object list;
{
register Lisp_Object tail, proptail;
+
for (tail = list; CONSP (tail); tail = XCDR (tail))
{
register Lisp_Object tem;
if (CONSP (tem) && EQ (propval, XCAR (tem)))
return 1;
}
+
if (CONSP (propval))
- for (proptail = propval; CONSP (proptail);
- proptail = XCDR (proptail))
- {
- Lisp_Object propelt;
- propelt = XCAR (proptail);
- for (tail = list; CONSP (tail); tail = XCDR (tail))
- {
- register Lisp_Object tem;
- tem = XCAR (tail);
- if (EQ (propelt, tem))
- return 1;
- if (CONSP (tem) && EQ (propelt, XCAR (tem)))
- return 1;
- }
- }
+ {
+ for (proptail = propval; CONSP (proptail); proptail = XCDR (proptail))
+ {
+ Lisp_Object propelt;
+ propelt = XCAR (proptail);
+ for (tail = list; CONSP (tail); tail = XCDR (tail))
+ {
+ register Lisp_Object tem;
+ tem = XCAR (tail);
+ if (EQ (propelt, tem))
+ return 1;
+ if (CONSP (tem) && EQ (propelt, XCAR (tem)))
+ return 1;
+ }
+ }
+ }
+
return 0;
}
staticpro (&Qtrailing_whitespace);
Qimage = intern ("image");
staticpro (&Qimage);
+ Qmessage_truncate_lines = intern ("message-truncate-lines");
+ staticpro (&Qmessage_truncate_lines);
last_arrow_position = Qnil;
last_arrow_string = Qnil;
staticpro (&echo_area_buffer[0]);
staticpro (&echo_area_buffer[1]);
+ Vmessages_buffer_name = build_string ("*Messages*");
+ staticpro (&Vmessages_buffer_name);
+
DEFVAR_LISP ("show-trailing-whitespace", &Vshow_trailing_whitespace,
"Non-nil means highlight trailing whitespace.\n\
The face used for trailing whitespace is `trailing-whitespace'.");
automatic_hscrolling_p = 1;
DEFVAR_LISP ("image-types", &Vimage_types,
- "List of supported image types.\n\
+ "List of supported image types.\n\
Each element of the list is a symbol for a supported image type.");
Vimage_types = Qnil;
+
+ DEFVAR_BOOL ("message-truncate-lines", &message_truncate_lines,
+ "If non-nil, messages are truncated instead of resizing the echo area.\n\
+Bind this around calls to `message' to let it take effect.");
+ message_truncate_lines = 0;
+
+ DEFVAR_LISP ("menu-bar-update-hook", &Vmenu_bar_update_hook,
+ "Normal hook run for clicks on menu bar, before displaying a submenu.\n\
+Can be used to update submenus whose contents should vary.");
+
}