#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"
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. */
#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 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));
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;
+
+ 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);
+ }
- /* Run the hook functions. */
- args[0] = Qfontification_functions;
- args[1] = pos;
- Frun_hook_with_args (2, args);
+ UNGCPRO;
+ }
+
+ unbind_to (count, Qnil);
/* Return HANDLED_RECOMPUTE_PROPS only if function fontified
something. This avoids an endless loop if they failed to
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. */
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, of course.
-
- Likewise if input is pending, because the pending input
- can have interrupted a previous redisplay, or redisplay
- wasn't called because of the pending input (see
- keyboard.c). In both cases, we would display the message
- fine, but the rest of the display would be garbage.
-
- Otherwise, we can do with updating just what we displayed
- above. */
+ int n = 0;
- if (window_height_changed_p || detect_input_pending ())
+ /* 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)
{
- int count = specpdl_ptr - specpdl;
-
- specbind (Qredisplay_dont_pause, Qt);
- ++windows_or_buffers_changed;
- ++update_mode_lines;
+ /* Must update other windows. */
+ windows_or_buffers_changed = 1;
redisplay_internal (0);
- unbind_to (count, Qnil);
}
- 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)
/* 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);
/* 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)
- goto try_to_scroll;
- row = MATRIX_ROW (w->current_matrix, w->last_cursor.vpos);
- if (row->mode_line_p)
- ++row;
- if (!row->enabled_p)
+ if (rc == -1)
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)
struct glyph_row *last_reused_text_row;
struct glyph_row *start_row;
int start_vpos, min_y, max_y;
-
if (/* This function doesn't handle terminal frames. */
!FRAME_WINDOW_P (f)
/* 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);
/* 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));
/* 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. */
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. */
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 %4d %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),
{
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. */
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. */
{
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;
}
"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.");
+
}