/* Display generation from window structure and buffer text.
-Copyright (C) 1985-1988, 1993-1995, 1997-2012 Free Software Foundation, Inc.
+Copyright (C) 1985-1988, 1993-1995, 1997-2013 Free Software Foundation,
+Inc.
This file is part of GNU Emacs.
#include <config.h>
#include <stdio.h>
#include <limits.h>
-#include <setjmp.h>
#include "lisp.h"
+#include "atimer.h"
#include "keyboard.h"
#include "frame.h"
#include "window.h"
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
-#ifdef WINDOWSNT
+#ifdef HAVE_NTGUI
#include "w32term.h"
#endif
#ifdef HAVE_NS
static Lisp_Object Qbuffer_position, Qposition, Qobject;
static Lisp_Object Qright_to_left, Qleft_to_right;
-/* Cursor shapes */
+/* Cursor shapes. */
Lisp_Object Qbar, Qhbar, Qbox, Qhollow;
-/* Pointer shapes */
+/* Pointer shapes. */
static Lisp_Object Qarrow, Qhand;
Lisp_Object Qtext;
static Lisp_Object Qwrap_prefix;
static Lisp_Object Qline_prefix;
+static Lisp_Object Qredisplay_internal;
/* Non-nil means don't actually do any redisplay. */
static Lisp_Object Qline_height;
/* These setters are used only in this file, so they can be private. */
-static inline void
+static void
wset_base_line_number (struct window *w, Lisp_Object val)
{
w->base_line_number = val;
}
-static inline void
+static void
wset_base_line_pos (struct window *w, Lisp_Object val)
{
w->base_line_pos = val;
}
-static inline void
+static void
wset_column_number_displayed (struct window *w, Lisp_Object val)
{
w->column_number_displayed = val;
}
-static inline void
+static void
wset_region_showing (struct window *w, Lisp_Object val)
{
w->region_showing = val;
static int overlay_arrow_seen;
-/* Number of windows showing the buffer of the selected window (or
- another buffer with the same base buffer). keyboard.c refers to
- this. */
-
-int buffer_shared;
-
/* Vector containing glyphs for an ellipsis `...'. */
static Lisp_Object default_invis_vector[3];
static void iterate_out_of_display_property (struct it *);
static void pop_it (struct it *);
static void sync_frame_with_window_matrix_rows (struct window *);
-static void select_frame_for_redisplay (Lisp_Object);
static void redisplay_internal (void);
static int echo_area_display (int);
static void redisplay_windows (Lisp_Object);
move_it_in_display_line_to (struct it *, ptrdiff_t, int,
enum move_operation_enum);
void move_it_vertically_backward (struct it *, int);
+static void get_visually_first_element (struct it *);
static void init_to_row_start (struct it *, struct window *,
struct glyph_row *);
static int init_to_row_end (struct it *, struct window *,
*BOTTOM_RIGHT_Y the coordinates of the bottom-right corner of the
box. */
-static inline void
+static void
window_box_edges (struct window *w, int area, int *top_left_x, int *top_left_y,
int *bottom_right_x, int *bottom_right_y)
{
/* Limit insanely large values of W->hscroll on frame F to the largest
value that will still prevent first_visible_x and last_visible_x of
'struct it' from overflowing an int. */
-static inline int
+static int
window_hscroll_limited (struct window *w, struct frame *f)
{
ptrdiff_t window_hscroll = w->hscroll;
BVAR (current_buffer, header_line_format));
start_display (&it, w, top);
- move_it_to (&it, charpos, -1, it.last_visible_y-1, -1,
+ move_it_to (&it, charpos, -1, it.last_visible_y - 1, -1,
(charpos >= 0 ? MOVE_TO_POS : 0) | MOVE_TO_Y);
if (charpos >= 0
&& IT_CHARPOS (it) >= charpos)
/* When scanning backwards under bidi iteration, move_it_to
stops at or _before_ CHARPOS, because it stops at or to
- the _right_ of the character at CHARPOS. */
+ the _right_ of the character at CHARPOS. */
|| (it.bidi_p && it.bidi_it.scan_dir == -1
&& IT_CHARPOS (it) <= charpos)))
{
returns an invalid character. If we find one, we return a `?', but
with the length of the invalid character. */
-static inline int
+static int
string_char_and_length (const unsigned char *str, int *len)
{
int c;
/* Value is the text position, i.e. character and byte position,
for character position CHARPOS in STRING. */
-static inline struct text_pos
+static struct text_pos
string_pos (ptrdiff_t charpos, Lisp_Object string)
{
struct text_pos pos;
#endif /* GLYPH_DEBUG and ENABLE_CHECKING */
+/* Return mark position if current buffer has the region of non-zero length,
+ or -1 otherwise. */
+
+static ptrdiff_t
+markpos_of_region (void)
+{
+ if (!NILP (Vtransient_mark_mode)
+ && !NILP (BVAR (current_buffer, mark_active))
+ && XMARKER (BVAR (current_buffer, mark))->buffer != NULL)
+ {
+ ptrdiff_t markpos = XMARKER (BVAR (current_buffer, mark))->charpos;
+
+ if (markpos != PT)
+ return markpos;
+ }
+ return -1;
+}
-\f
/***********************************************************************
Iterator initialization
***********************************************************************/
ptrdiff_t charpos, ptrdiff_t bytepos,
struct glyph_row *row, enum face_id base_face_id)
{
- int highlight_region_p;
+ ptrdiff_t markpos;
enum face_id remapped_base_face_id = base_face_id;
/* Some precondition checks. */
/* Are multibyte characters enabled in current_buffer? */
it->multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters));
- /* Non-zero if we should highlight the region. */
- highlight_region_p
- = (!NILP (Vtransient_mark_mode)
- && !NILP (BVAR (current_buffer, mark_active))
- && XMARKER (BVAR (current_buffer, mark))->buffer != 0);
-
- /* Set IT->region_beg_charpos and IT->region_end_charpos to the
- start and end of a visible region in window IT->w. Set both to
- -1 to indicate no region. */
- if (highlight_region_p
+ /* If visible region is of non-zero length, set IT->region_beg_charpos
+ and IT->region_end_charpos to the start and end of a visible region
+ in window IT->w. Set both to -1 to indicate no region. */
+ markpos = markpos_of_region ();
+ if (0 <= markpos
/* Maybe highlight only in selected window. */
&& (/* Either show region everywhere. */
highlight_nonselected_windows
&& WINDOWP (minibuf_selected_window)
&& w == XWINDOW (minibuf_selected_window))))
{
- ptrdiff_t markpos = marker_position (BVAR (current_buffer, mark));
it->region_beg_charpos = min (PT, markpos);
it->region_end_charpos = max (PT, markpos);
}
eassert (STRINGP (it->string));
it->current.string_pos = pos->string_pos;
it->method = GET_FROM_STRING;
+ it->end_charpos = SCHARS (it->string);
+ /* Set up the bidi iterator for this overlay string. */
+ if (it->bidi_p)
+ {
+ it->bidi_it.string.lstring = it->string;
+ it->bidi_it.string.s = NULL;
+ it->bidi_it.string.schars = SCHARS (it->string);
+ it->bidi_it.string.bufpos = it->overlay_strings_charpos;
+ it->bidi_it.string.from_disp_str = it->string_from_display_prop_p;
+ it->bidi_it.string.unibyte = !it->multibyte_p;
+ bidi_init_it (IT_STRING_CHARPOS (*it), IT_STRING_BYTEPOS (*it),
+ FRAME_WINDOW_P (it->f), &it->bidi_it);
+
+ /* Synchronize the state of the bidi iterator with
+ pos->string_pos. For any string position other than
+ zero, this will be done automagically when we resume
+ iteration over the string and get_visually_first_element
+ is called. But if string_pos is zero, and the string is
+ to be reordered for display, we need to resync manually,
+ since it could be that the iteration state recorded in
+ pos ended at string_pos of 0 moving backwards in string. */
+ if (CHARPOS (pos->string_pos) == 0)
+ {
+ get_visually_first_element (it);
+ if (IT_STRING_CHARPOS (*it) != 0)
+ do {
+ /* Paranoia. */
+ eassert (it->bidi_it.charpos < it->bidi_it.string.schars);
+ bidi_move_to_visually_next (&it->bidi_it);
+ } while (it->bidi_it.charpos != 0);
+ }
+ eassert (IT_STRING_CHARPOS (*it) == it->bidi_it.charpos
+ && IT_STRING_BYTEPOS (*it) == it->bidi_it.bytepos);
+ }
}
if (CHARPOS (pos->string_pos) >= 0)
IT should already be filled with that string. */
it->current.string_pos = pos->string_pos;
eassert (STRINGP (it->string));
+ if (it->bidi_p)
+ bidi_init_it (IT_STRING_CHARPOS (*it), IT_STRING_BYTEPOS (*it),
+ FRAME_WINDOW_P (it->f), &it->bidi_it);
}
/* Restore position in display vector translations, control
}
/* There isn't much we can reasonably do to protect against
misbehaving fontification, but here's a fig leaf. */
- else if (!NILP (BVAR (obuf, name)))
+ else if (BUFFER_LIVE_P (obuf))
set_buffer_internal_1 (obuf);
/* The fontification code may have added/removed text.
if (new_face_id != it->face_id)
{
struct face *new_face = FACE_FROM_ID (it->f, new_face_id);
+ /* If it->face_id is -1, old_face below will be NULL, see
+ the definition of FACE_FROM_ID. This will happen if this
+ is the initial call that gets the face. */
+ struct face *old_face = FACE_FROM_ID (it->f, it->face_id);
- /* If new face has a box but old face has not, this is
- the start of a run of characters with box, i.e. it has
- a shadow on the left side. The value of face_id of the
- iterator will be -1 if this is the initial call that gets
- the face. In this case, we have to look in front of IT's
- position and see whether there is a face != new_face_id. */
- it->start_of_box_run_p
- = (new_face->box != FACE_NO_BOX
- && (it->face_id >= 0
- || IT_CHARPOS (*it) == BEG
- || new_face_id != face_before_it_pos (it)));
+ /* If the value of face_id of the iterator is -1, we have to
+ look in front of IT's position and see whether there is a
+ face there that's different from new_face_id. */
+ if (!old_face && IT_CHARPOS (*it) > BEG)
+ {
+ int prev_face_id = face_before_it_pos (it);
+
+ old_face = FACE_FROM_ID (it->f, prev_face_id);
+ }
+
+ /* If the new face has a box, but the old face does not,
+ this is the start of a run of characters with box face,
+ i.e. this character has a shadow on the left side. */
+ it->start_of_box_run_p = (new_face->box != FACE_NO_BOX
+ && (old_face == NULL || !old_face->box));
it->face_box_p = new_face->box != FACE_NO_BOX;
}
}
SET_TEXT_POS (it->current.string_pos, 0, 0);
it->method = GET_FROM_STRING;
it->stop_charpos = 0;
+ it->end_charpos = SCHARS (it->string);
if (it->cmp_it.stop_pos >= 0)
it->cmp_it.stop_pos = 0;
it->prev_stop = 0;
it->stop_charpos = CHARPOS (pos);
it->base_level_stop = CHARPOS (pos);
}
+ /* This make the information stored in it->cmp_it invalidate. */
+ it->cmp_it.id = -1;
}
default:
/* There are no other methods defined, so this should be a bug. */
- abort ();
+ emacs_abort ();
}
eassert (it->method != GET_FROM_STRING
{
it->end_charpos = min (charpos + 1, ZV);
charpos = max (charpos - SCAN_BACK_LIMIT, BEGV);
- SET_TEXT_POS (pos, charpos, BYTE_TO_CHAR (charpos));
+ SET_TEXT_POS (pos, charpos, CHAR_TO_BYTE (charpos));
reseat_1 (it, pos, 0);
compute_stop_pos (it);
/* We must advance forward, right? */
if (it->stop_charpos <= charpos)
- abort ();
+ emacs_abort ();
}
while (charpos > BEGV && it->stop_charpos >= it->end_charpos);
compute_stop_pos (it);
/* We must advance forward, right? */
if (it->stop_charpos <= it->prev_stop)
- abort ();
+ emacs_abort ();
charpos = it->stop_charpos;
}
while (charpos <= where_we_are);
break;
default:
- abort ();
+ emacs_abort ();
}
/* Reset/increment for the next run. */
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
USE_SAFE_ALLOCA;
- /* Do nothing if called asynchronously. Inserting text into
- a buffer may call after-change-functions and alike and
- that would means running Lisp asynchronously. */
- if (handling_signal)
- return;
-
fmt = msg = Qnil;
GCPRO4 (fmt, msg, arg1, arg2);
int old_windows_or_buffers_changed = windows_or_buffers_changed;
ptrdiff_t point_at_end = 0;
ptrdiff_t zv_at_end = 0;
- Lisp_Object old_deactivate_mark, tem;
+ Lisp_Object old_deactivate_mark;
+ bool shown;
struct gcpro gcpro1;
old_deactivate_mark = Vdeactivate_mark;
del_range_both (BEG, BEG_BYTE, PT, PT_BYTE, 0);
}
}
- BEGV = XMARKER (oldbegv)->charpos;
+ BEGV = marker_position (oldbegv);
BEGV_BYTE = marker_byte_position (oldbegv);
if (zv_at_end)
}
else
{
- ZV = XMARKER (oldzv)->charpos;
+ ZV = marker_position (oldzv);
ZV_BYTE = marker_byte_position (oldzv);
}
else
/* We can't do Fgoto_char (oldpoint) because it will run some
Lisp code. */
- TEMP_SET_PT_BOTH (XMARKER (oldpoint)->charpos,
- XMARKER (oldpoint)->bytepos);
+ TEMP_SET_PT_BOTH (marker_position (oldpoint),
+ marker_byte_position (oldpoint));
UNGCPRO;
unchain_marker (XMARKER (oldpoint));
unchain_marker (XMARKER (oldbegv));
unchain_marker (XMARKER (oldzv));
- tem = Fget_buffer_window (Fcurrent_buffer (), Qt);
+ shown = buffer_window_count (current_buffer) > 0;
set_buffer_internal (oldbuf);
- if (NILP (tem))
+ if (!shown)
windows_or_buffers_changed = old_windows_or_buffers_changed;
message_log_need_newline = !nlflag;
Vdeactivate_mark = old_deactivate_mark;
do_pending_window_change (0);
echo_area_display (1);
do_pending_window_change (0);
- if (FRAME_TERMINAL (f)->frame_up_to_date_hook != 0 && ! gc_in_progress)
+ if (FRAME_TERMINAL (f)->frame_up_to_date_hook)
(*FRAME_TERMINAL (f)->frame_up_to_date_hook) (f);
}
}
do_pending_window_change (0);
echo_area_display (1);
do_pending_window_change (0);
- if (FRAME_TERMINAL (f)->frame_up_to_date_hook != 0 && ! gc_in_progress)
+ if (FRAME_TERMINAL (f)->frame_up_to_date_hook)
(*FRAME_TERMINAL (f)->frame_up_to_date_hook) (f);
}
}
for (i = 0; i < 2; ++i)
if (!BUFFERP (echo_buffer[i])
- || NILP (BVAR (XBUFFER (echo_buffer[i]), name)))
+ || !BUFFER_LIVE_P (XBUFFER (echo_buffer[i])))
{
char name[30];
Lisp_Object old_buffer;
{
XSETWINDOW (tmp, w); ASET (vector, i, tmp); ++i;
ASET (vector, i, w->buffer); ++i;
- ASET (vector, i, make_number (XMARKER (w->pointm)->charpos)); ++i;
- ASET (vector, i, make_number (XMARKER (w->pointm)->bytepos)); ++i;
+ ASET (vector, i, make_number (marker_position (w->pointm))); ++i;
+ ASET (vector, i, make_number (marker_byte_position (w->pointm))); ++i;
}
else
{
max_height = total_height / 4;
/* Correct that max. height if it's bogus. */
- max_height = max (1, max_height);
- max_height = min (total_height, max_height);
+ max_height = clip_to_bounds (1, max_height, total_height);
/* Find out the height of the text in the window. */
if (it.line_wrap == TRUNCATE)
check_message_stack (void)
{
if (!NILP (Vmessage_stack))
- abort ();
+ emacs_abort ();
}
return 0;
}
-
/* Set the current message to a substring of S or STRING.
If STRING is a Lisp string, set the message to the first NBYTES
(intptr_t) s, string, nbytes, multibyte_p);
message_buf_print = 0;
help_echo_showing_p = 0;
+
+ if (STRINGP (Vdebug_on_message)
+ && fast_string_match (Vdebug_on_message, string) >= 0)
+ call_debugger (list2 (Qerror, string));
}
{
if (f->resized_p)
{
- Fredraw_frame (frame);
+ redraw_frame (f);
f->force_flush_display_p = 1;
}
clear_current_matrices (f);
#endif /* HAVE_WINDOW_SYSTEM */
/* Redraw garbaged frames. */
- if (frame_garbaged)
- clear_garbaged_frames ();
+ clear_garbaged_frames ();
if (!NILP (echo_area_buffer[0]) || minibuf_level == 0)
{
return window_height_changed_p;
}
+/* Nonzero if the current window's buffer is shown in more than one
+ window and was modified since last redisplay. */
+
+static int
+buffer_shared_and_changed (void)
+{
+ return (buffer_window_count (current_buffer) > 1
+ && UNCHANGED_MODIFIED < MODIFF);
+}
+
+/* Nonzero if W doesn't reflect the actual state of current buffer due
+ to its text or overlays change. FIXME: this may be called when
+ XBUFFER (w->buffer) != current_buffer, which looks suspicious. */
+
+static int
+window_outdated (struct window *w)
+{
+ return (w->last_modified < MODIFF
+ || w->last_overlay_modified < OVERLAY_MODIFF);
+}
+
+/* Nonzero if W's buffer was changed but not saved or Transient Mark mode
+ is enabled and mark of W's buffer was changed since last W's update. */
+
+static int
+window_buffer_changed (struct window *w)
+{
+ struct buffer *b = XBUFFER (w->buffer);
+
+ eassert (BUFFER_LIVE_P (b));
+
+ return (((BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)) != w->last_had_star)
+ || ((!NILP (Vtransient_mark_mode) && !NILP (BVAR (b, mark_active)))
+ != !NILP (w->region_showing)));
+}
+
+/* Nonzero if W has %c in its mode line and mode line should be updated. */
+
+static int
+mode_line_update_needed (struct window *w)
+{
+ return (!NILP (w->column_number_displayed)
+ && !(PT == w->last_point && !window_outdated (w))
+ && (XFASTINT (w->column_number_displayed) != current_column ()));
+}
-\f
/***********************************************************************
Mode Lines and Frame Titles
***********************************************************************/
|| f->explicit_name)
{
/* Do we have more than one visible frame on this X display? */
- Lisp_Object tail;
- Lisp_Object fmt;
+ Lisp_Object tail, other_frame, fmt;
ptrdiff_t title_start;
char *title;
ptrdiff_t len;
struct it it;
ptrdiff_t count = SPECPDL_INDEX ();
- for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
+ FOR_EACH_FRAME (tail, other_frame)
{
- Lisp_Object other_frame = XCAR (tail);
struct frame *tf = XFRAME (other_frame);
if (tf != f
/* Update the menu bar item lists, if appropriate. This has to be
done before any actual redisplay or generation of display lines. */
all_windows = (update_mode_lines
- || buffer_shared > 1
+ || buffer_shared_and_changed ()
|| windows_or_buffers_changed);
if (all_windows)
{
/* This used to test w->update_mode_line, but we believe
there is no need to recompute the menu in that case. */
|| update_mode_lines
- || ((BUF_SAVE_MODIFF (XBUFFER (w->buffer))
- < BUF_MODIFF (XBUFFER (w->buffer)))
- != w->last_had_star)
- || ((!NILP (Vtransient_mark_mode)
- && !NILP (BVAR (XBUFFER (w->buffer), mark_active)))
- != !NILP (w->region_showing)))
+ || window_buffer_changed (w))
{
struct buffer *prev = current_buffer;
ptrdiff_t count = SPECPDL_INDEX ();
This will also set the cursor position of W. */
if (updated_window == NULL)
{
- BLOCK_INPUT;
+ block_input ();
display_and_set_cursor (w, 1, hpos, vpos, x, y);
if (FRAME_RIF (SELECTED_FRAME ())->flush_display_optional)
FRAME_RIF (SELECTED_FRAME ())->flush_display_optional (SELECTED_FRAME ());
- UNBLOCK_INPUT;
+ unblock_input ();
}
}
int last_tool_bar_item;
-
+/* Select `frame' temporarily without running all the code in
+ do_switch_frame.
+ FIXME: Maybe do_switch_frame should be trimmed down similarly
+ when `norecord' is set. */
static Lisp_Object
-update_tool_bar_unwind (Lisp_Object frame)
+fast_set_selected_frame (Lisp_Object frame)
{
- selected_frame = frame;
+ if (!EQ (selected_frame, frame))
+ {
+ selected_frame = frame;
+ selected_window = XFRAME (frame)->selected_window;
+ }
return Qnil;
}
if (windows_or_buffers_changed
|| w->update_mode_line
|| update_mode_lines
- || ((BUF_SAVE_MODIFF (XBUFFER (w->buffer))
- < BUF_MODIFF (XBUFFER (w->buffer)))
- != w->last_had_star)
- || ((!NILP (Vtransient_mark_mode)
- && !NILP (BVAR (XBUFFER (w->buffer), mark_active)))
- != !NILP (w->region_showing)))
+ || window_buffer_changed (w))
{
struct buffer *prev = current_buffer;
ptrdiff_t count = SPECPDL_INDEX ();
before calling tool_bar_items, because the calculation of
the tool-bar keymap uses the selected frame (see
`tool-bar-make-keymap' in tool-bar.el). */
- record_unwind_protect (update_tool_bar_unwind, selected_frame);
+ eassert (EQ (selected_window,
+ /* Since we only explicitly preserve selected_frame,
+ check that selected_window would be redundant. */
+ XFRAME (selected_frame)->selected_window));
+ record_unwind_protect (fast_set_selected_frame, selected_frame);
XSETFRAME (frame, f);
- selected_frame = frame;
+ fast_set_selected_frame (frame);
/* Build desired tool-bar items from keymaps. */
new_tool_bar
/* Redisplay that happens asynchronously due to an expose event
may access f->tool_bar_items. Make sure we update both
variables within BLOCK_INPUT so no such event interrupts. */
- BLOCK_INPUT;
+ block_input ();
fset_tool_bar_items (f, new_tool_bar);
f->n_tool_bar_items = new_n_tool_bar;
w->update_mode_line = 1;
- UNBLOCK_INPUT;
+ unblock_input ();
}
UNGCPRO;
DEFUN ("tool-bar-lines-needed", Ftool_bar_lines_needed, Stool_bar_lines_needed,
0, 1, 0,
- doc: /* Return the number of lines occupied by the tool bar of FRAME. */)
+ doc: /* Return the number of lines occupied by the tool bar of FRAME.
+If FRAME is nil or omitted, use the selected frame. */)
(Lisp_Object frame)
{
- struct frame *f;
+ struct frame *f = decode_any_frame (frame);
struct window *w;
int nlines = 0;
- if (NILP (frame))
- frame = selected_frame;
- else
- CHECK_FRAME (frame);
- f = XFRAME (frame);
-
if (WINDOWP (f->tool_bar_window)
&& (w = XWINDOW (f->tool_bar_window),
WINDOW_TOTAL_LINES (w) > 0))
{
/* Show item in pressed state. */
show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN);
- hlinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
last_tool_bar_item = prop_idx;
}
else
/* Show item in released state. */
show_mouse_face (hlinfo, DRAW_IMAGE_RAISED);
- hlinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
&& last_tool_bar_item != prop_idx)
return;
- hlinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
/* If tool-bar item is not enabled, don't highlight it. */
/* Display it as active. */
show_mouse_face (hlinfo, draw);
- hlinfo->mouse_face_image_state = draw;
}
set_help_echo:
if (w == XWINDOW (selected_window))
pt = PT;
else
- {
- pt = marker_position (w->pointm);
- pt = max (BEGV, pt);
- pt = min (ZV, pt);
- }
+ pt = clip_to_bounds (BEGV, marker_position (w->pointm), ZV);
/* Move iterator to pt starting at cursor_row->start in
a line with infinite width. */
buffer position, END is given as a distance from Z. Used in
redisplay_internal for display optimization. */
-static inline int
+static int
text_outside_line_unchanged_p (struct window *w,
ptrdiff_t start, ptrdiff_t end)
{
int unchanged_p = 1;
/* If text or overlays have changed, see where. */
- if (w->last_modified < MODIFF
- || w->last_overlay_modified < OVERLAY_MODIFF)
+ if (window_outdated (w))
{
/* Gap in the line? */
if (GPT < start || Z - GPT < end)
return make_number (fringe_bitmap);
}
#endif
- return make_number (-1); /* Use default arrow bitmap */
+ return make_number (-1); /* Use default arrow bitmap. */
}
return overlay_arrow_string_or_property (var);
}
/* Reconsider the setting of B->clip_changed which is displayed
in window W. */
-static inline void
+static void
reconsider_clip_changes (struct window *w, struct buffer *b)
{
if (b->clip_changed
}
\f
-/* Select FRAME to forward the values of frame-local variables into C
- variables so that the redisplay routines can access those values
- directly. */
-
-static void
-select_frame_for_redisplay (Lisp_Object frame)
-{
- Lisp_Object tail, tem;
- Lisp_Object old = selected_frame;
- struct Lisp_Symbol *sym;
-
- eassert (FRAMEP (frame) && FRAME_LIVE_P (XFRAME (frame)));
-
- selected_frame = frame;
-
- do {
- for (tail = XFRAME (frame)->param_alist;
- CONSP (tail); tail = XCDR (tail))
- if (CONSP (XCAR (tail))
- && (tem = XCAR (XCAR (tail)),
- SYMBOLP (tem))
- && (sym = indirect_variable (XSYMBOL (tem)),
- sym->redirect == SYMBOL_LOCALIZED)
- && sym->val.blv->frame_local)
- /* Use find_symbol_value rather than Fsymbol_value
- to avoid an error if it is void. */
- find_symbol_value (tem);
- } while (!EQ (frame, old) && (frame = old, 1));
-}
-
-
#define STOP_POLLING \
do { if (! polling_stopped_here) stop_polling (); \
polling_stopped_here = 1; } while (0)
ptrdiff_t count, count1;
struct frame *sf;
int polling_stopped_here = 0;
- Lisp_Object old_frame = selected_frame;
+ Lisp_Object tail, frame;
+ struct backtrace backtrace;
/* Non-zero means redisplay has to consider all windows on all
frames. Zero means, only selected_window is considered. */
int consider_all_windows_p;
- /* Non-zero means redisplay has to redisplay the miniwindow */
+ /* Non-zero means redisplay has to redisplay the miniwindow. */
int update_miniwindow_p = 0;
TRACE ((stderr, "redisplay_internal %d\n", redisplaying_p));
redisplaying_p = 1;
specbind (Qinhibit_free_realized_faces, Qnil);
- {
- Lisp_Object tail, frame;
+ /* Record this function, so it appears on the profiler's backtraces. */
+ backtrace.next = backtrace_list;
+ backtrace.function = Qredisplay_internal;
+ backtrace.args = &Qnil;
+ backtrace.nargs = 0;
+ backtrace.debug_on_exit = 0;
+ backtrace_list = &backtrace;
- FOR_EACH_FRAME (tail, frame)
- {
- struct frame *f = XFRAME (frame);
- f->already_hscrolled_p = 0;
- }
- }
+ FOR_EACH_FRAME (tail, frame)
+ XFRAME (frame)->already_hscrolled_p = 0;
retry:
/* Remember the currently selected window. */
sw = w;
- if (!EQ (old_frame, selected_frame)
- && FRAME_LIVE_P (XFRAME (old_frame)))
- /* When running redisplay, we play a bit fast-and-loose and allow e.g.
- selected_frame and selected_window to be temporarily out-of-sync so
- when we come back here via `goto retry', we need to resync because we
- may need to run Elisp code (via prepare_menu_bars). */
- select_frame_for_redisplay (old_frame);
-
pending = 0;
reconsider_clip_changes (w, current_buffer);
last_escape_glyph_frame = NULL;
FRAME_TTY (sf)->previous_frame = sf;
}
- /* Set the visible flags for all frames. Do this before checking
- for resized or garbaged frames; they want to know if their frames
- are visible. See the comment in frame.h for
- FRAME_SAMPLE_VISIBILITY. */
- {
- Lisp_Object tail, frame;
-
- number_of_visible_frames = 0;
+ /* Set the visible flags for all frames. Do this before checking for
+ resized or garbaged frames; they want to know if their frames are
+ visible. See the comment in frame.h for FRAME_SAMPLE_VISIBILITY. */
+ number_of_visible_frames = 0;
- FOR_EACH_FRAME (tail, frame)
- {
- struct frame *f = XFRAME (frame);
+ FOR_EACH_FRAME (tail, frame)
+ {
+ struct frame *f = XFRAME (frame);
- FRAME_SAMPLE_VISIBILITY (f);
- if (FRAME_VISIBLE_P (f))
- ++number_of_visible_frames;
- clear_desired_matrices (f);
- }
- }
+ FRAME_SAMPLE_VISIBILITY (f);
+ if (FRAME_VISIBLE_P (f))
+ ++number_of_visible_frames;
+ clear_desired_matrices (f);
+ }
/* Notice any pending interrupt request to change frame size. */
do_pending_window_change (1);
}
/* Clear frames marked as garbaged. */
- if (frame_garbaged)
- clear_garbaged_frames ();
+ clear_garbaged_frames ();
/* Build menubar and tool-bar items. */
if (NILP (Vmemory_full))
if ((SAVE_MODIFF < MODIFF) != w->last_had_star)
{
w->update_mode_line = 1;
- if (buffer_shared > 1)
+ if (buffer_shared_and_changed ())
update_mode_lines++;
}
count1 = SPECPDL_INDEX ();
specbind (Qinhibit_point_motion_hooks, Qt);
- /* If %c is in the mode line, update it if needed. */
- if (!NILP (w->column_number_displayed)
- /* This alternative quickly identifies a common case
- where no change is needed. */
- && !(PT == w->last_point
- && w->last_modified >= MODIFF
- && w->last_overlay_modified >= OVERLAY_MODIFF)
- && (XFASTINT (w->column_number_displayed) != current_column ()))
+ if (mode_line_update_needed (w))
w->update_mode_line = 1;
unbind_to (count1, Qnil);
FRAME_SCROLL_BOTTOM_VPOS (XFRAME (w->frame)) = -1;
- /* The variable buffer_shared is set in redisplay_window and
- indicates that we redisplay a buffer in different windows. See
- there. */
- consider_all_windows_p = (update_mode_lines || buffer_shared > 1
+ consider_all_windows_p = (update_mode_lines
+ || buffer_shared_and_changed ()
|| cursor_type_changed);
/* If specs for an arrow have changed, do thorough redisplay
/* If window configuration was changed, frames may have been
marked garbaged. Clear them or we will experience
surprises wrt scrolling. */
- if (frame_garbaged)
- clear_garbaged_frames ();
+ clear_garbaged_frames ();
}
}
else if (EQ (selected_window, minibuf_window)
- && (current_buffer->clip_changed
- || w->last_modified < MODIFF
- || w->last_overlay_modified < OVERLAY_MODIFF)
+ && (current_buffer->clip_changed || window_outdated (w))
&& resize_mini_window (w, 0))
{
/* Resized active mini-window to fit the size of what it is
showing if its contents might have changed. */
must_finish = 1;
-/* FIXME: this causes all frames to be updated, which seems unnecessary
- since only the current frame needs to be considered. This function needs
- to be rewritten with two variables, consider_all_windows and
- consider_all_frames. */
+ /* FIXME: this causes all frames to be updated, which seems unnecessary
+ since only the current frame needs to be considered. This function
+ needs to be rewritten with two variables, consider_all_windows and
+ consider_all_frames. */
consider_all_windows_p = 1;
++windows_or_buffers_changed;
++update_mode_lines;
/* If window configuration was changed, frames may have been
marked garbaged. Clear them or we will experience
surprises wrt scrolling. */
- if (frame_garbaged)
- clear_garbaged_frames ();
+ clear_garbaged_frames ();
}
|| FETCH_BYTE (BYTEPOS (tlbufpos)) == '\n'))
/* Former continuation line has disappeared by becoming empty. */
goto cancel;
- else if (w->last_modified < MODIFF
- || w->last_overlay_modified < OVERLAY_MODIFF
- || MINI_WINDOW_P (w))
+ else if (window_outdated (w) || MINI_WINDOW_P (w))
{
/* We have to handle the case of continuation around a
wide-column character (see the comment in indent.c around
}
CHARPOS (this_line_start_pos) = 0;
- consider_all_windows_p |= buffer_shared > 1;
+ consider_all_windows_p |= buffer_shared_and_changed ();
++clear_face_cache_count;
#ifdef HAVE_WINDOW_SYSTEM
++clear_image_cache_count;
if (consider_all_windows_p)
{
- Lisp_Object tail, frame;
-
FOR_EACH_FRAME (tail, frame)
XFRAME (frame)->updated_p = 0;
- /* Recompute # windows showing selected buffer. This will be
- incremented each time such a window is displayed. */
- buffer_shared = 0;
-
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
if (FRAME_WINDOW_P (f) || FRAME_TERMCAP_P (f) || f == sf)
{
- if (! EQ (frame, selected_frame))
- /* Select the frame, for the sake of frame-local
- variables. */
- select_frame_for_redisplay (frame);
-
/* Mark all the scroll bars to be removed; we'll redeem
the ones we want when we redisplay their windows. */
if (FRAME_TERMINAL (f)->condemn_scroll_bars_hook)
}
}
- if (!EQ (old_frame, selected_frame)
- && FRAME_LIVE_P (XFRAME (old_frame)))
- /* We played a bit fast-and-loose above and allowed selected_frame
- and selected_window to be temporarily out-of-sync but let's make
- sure this stays contained. */
- select_frame_for_redisplay (old_frame);
- eassert (EQ (XFRAME (selected_frame)->selected_window,
- selected_window));
+ eassert (EQ (XFRAME (selected_frame)->selected_window, selected_window));
if (!pending)
{
}
else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
{
- Lisp_Object mini_window;
+ Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf);
struct frame *mini_frame;
- mini_window = FRAME_MINIBUF_WINDOW (sf);
displayed_buffer = XBUFFER (XWINDOW (selected_window)->buffer);
/* Use list_of_error, not Qerror, so that
we catch only errors and don't run the debugger. */
frames here explicitly. */
if (!pending)
{
- Lisp_Object tail, frame;
int new_count = 0;
FOR_EACH_FRAME (tail, frame)
#endif /* HAVE_WINDOW_SYSTEM */
end_of_redisplay:
+ backtrace_list = backtrace.next;
unbind_to (count, Qnil);
RESUME_POLLING;
}
/* Function registered with record_unwind_protect in redisplay_internal.
- Clear redisplaying_p. Also, select the previously
- selected frame, unless it has been deleted (by an X connection
- failure during redisplay, for example). */
+ Clear redisplaying_p. Also select the previously selected frame. */
static Lisp_Object
unwind_redisplay (Lisp_Object old_frame)
{
redisplaying_p = 0;
- if (! EQ (old_frame, selected_frame)
- && FRAME_LIVE_P (XFRAME (old_frame)))
- select_frame_for_redisplay (old_frame);
return Qnil;
}
{
struct buffer *b = XBUFFER (w->buffer);
- w->last_modified = accurate_p ? BUF_MODIFF(b) : 0;
- w->last_overlay_modified = accurate_p ? BUF_OVERLAY_MODIFF(b) : 0;
+ w->last_modified = accurate_p ? BUF_MODIFF (b) : 0;
+ w->last_overlay_modified = accurate_p ? BUF_OVERLAY_MODIFF (b) : 0;
w->last_had_star
= BUF_MODIFF (b) > BUF_SAVE_MODIFF (b);
if (w == XWINDOW (selected_window))
w->last_point = BUF_PT (b);
else
- w->last_point = XMARKER (w->pointm)->charpos;
+ w->last_point = marker_position (w->pointm);
}
}
GLYPH_BEFORE and GLYPH_AFTER. */
if (!((row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end)
&& BUFFERP (glyph->object) && glyph->charpos == pt_old)
- && bpos_covered < pt_old)
+ && !(bpos_max < pt_old && pt_old <= bpos_covered))
{
/* An empty line has a single glyph whose OBJECT is zero and
whose CHARPOS is the position of a newline on that line.
CHARPOS is zero or negative. */
int empty_line_p =
(row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end)
- && INTEGERP (glyph->object) && glyph->charpos > 0;
+ && INTEGERP (glyph->object) && glyph->charpos > 0
+ /* On a TTY, continued and truncated rows also have a glyph at
+ their end whose OBJECT is zero and whose CHARPOS is
+ positive (the continuation and truncation glyphs), but such
+ rows are obviously not "empty". */
+ && !(row->continued_p || row->truncated_on_right_p);
if (row->ends_in_ellipsis_p && pos_after == last_pos)
{
for (g = row->glyphs[TEXT_AREA], x = row->x; g < glyph; g++)
{
if (g >= row->glyphs[TEXT_AREA] + row->used[TEXT_AREA])
- abort ();
+ emacs_abort ();
x += g->pixel_width;
}
}
We assume that the window's buffer is really current. */
-static inline struct text_pos
+static struct text_pos
run_window_scroll_functions (Lisp_Object window, struct text_pos startp)
{
struct window *w = XWINDOW (window);
SET_MARKER_FROM_TEXT_POS (w->start, startp);
if (current_buffer != XBUFFER (w->buffer))
- abort ();
+ emacs_abort ();
if (!NILP (Vwindow_scroll_functions))
{
if (NUMBERP (aggressive))
{
double float_amount = XFLOATINT (aggressive) * height;
- amount_to_scroll = float_amount;
- if (amount_to_scroll == 0 && float_amount > 0)
- amount_to_scroll = 1;
+ int aggressive_scroll = float_amount;
+ if (aggressive_scroll == 0 && float_amount > 0)
+ aggressive_scroll = 1;
/* Don't let point enter the scroll margin near top of
- the window. */
- if (amount_to_scroll > height - 2*this_scroll_margin + dy)
- amount_to_scroll = height - 2*this_scroll_margin + dy;
+ the window. This could happen if the value of
+ scroll_up_aggressively is too large and there are
+ non-zero margins, because scroll_up_aggressively
+ means put point that fraction of window height
+ _from_the_bottom_margin_. */
+ if (aggressive_scroll + 2*this_scroll_margin > height)
+ aggressive_scroll = height - 2*this_scroll_margin;
+ amount_to_scroll = dy + aggressive_scroll;
}
}
/* Compute the vertical distance from PT to the scroll
margin position. Move as far as scroll_max allows, or
one screenful, or 10 screen lines, whichever is largest.
- Give up if distance is greater than scroll_max. */
+ Give up if distance is greater than scroll_max or if we
+ didn't reach the scroll margin position. */
SET_TEXT_POS (pos, PT, PT_BYTE);
start_display (&it, w, pos);
y0 = it.current_y;
y_to_move, -1,
MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
dy = it.current_y - y0;
- if (dy > scroll_max)
+ if (dy > scroll_max
+ || IT_CHARPOS (it) < CHARPOS (scroll_margin_pos))
return SCROLLING_FAILED;
/* Compute new window start. */
if (NUMBERP (aggressive))
{
double float_amount = XFLOATINT (aggressive) * height;
- amount_to_scroll = float_amount;
- if (amount_to_scroll == 0 && float_amount > 0)
- amount_to_scroll = 1;
- amount_to_scroll -=
- this_scroll_margin - dy - FRAME_LINE_HEIGHT (f);
+ int aggressive_scroll = float_amount;
+ if (aggressive_scroll == 0 && float_amount > 0)
+ aggressive_scroll = 1;
/* Don't let point enter the scroll margin near
- bottom of the window. */
- if (amount_to_scroll > height - 2*this_scroll_margin + dy)
- amount_to_scroll = height - 2*this_scroll_margin + dy;
+ bottom of the window, if the value of
+ scroll_down_aggressively happens to be too
+ large. */
+ if (aggressive_scroll + 2*this_scroll_margin > height)
+ aggressive_scroll = height - 2*this_scroll_margin;
+ amount_to_scroll = dy + aggressive_scroll;
}
}
/* 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 (BVAR (current_buffer, mark_active)))
+ && markpos_of_region () < 0
&& NILP (w->region_showing)
&& NILP (Vshow_trailing_whitespace)
/* This code is not used for mini-buffer for the sake of the case
= (!NILP (w->window_end_valid)
&& !current_buffer->clip_changed
&& !current_buffer->prevent_redisplay_optimizations_p
- && w->last_modified >= MODIFF
- && w->last_overlay_modified >= OVERLAY_MODIFF);
+ && !window_outdated (w));
/* Run the window-bottom-change-functions
if it is possible that the text on the screen has changed
buffer_unchanged_p
= (!NILP (w->window_end_valid)
&& !current_buffer->clip_changed
- && w->last_modified >= MODIFF
- && w->last_overlay_modified >= OVERLAY_MODIFF);
+ && !window_outdated (w));
/* When windows_or_buffers_changed is non-zero, we can't rely on
the window end being valid, so set it to nil there. */
/* Some sanity checks. */
CHECK_WINDOW_END (w);
if (Z == Z_BYTE && CHARPOS (opoint) != BYTEPOS (opoint))
- abort ();
+ emacs_abort ();
if (BYTEPOS (opoint) < CHARPOS (opoint))
- abort ();
-
- /* If %c is in mode line, update it if needed. */
- if (!NILP (w->column_number_displayed)
- /* This alternative quickly identifies a common case
- where no change is needed. */
- && !(PT == w->last_point
- && w->last_modified >= MODIFF
- && w->last_overlay_modified >= OVERLAY_MODIFF)
- && (XFASTINT (w->column_number_displayed) != current_column ()))
- update_mode_line = 1;
+ emacs_abort ();
- /* Count number of windows showing the selected buffer. An indirect
- buffer counts as its base buffer. */
- if (!just_this_one_p)
- {
- struct buffer *current_base, *window_base;
- current_base = current_buffer;
- window_base = XBUFFER (XWINDOW (selected_window)->buffer);
- if (current_base->base_buffer)
- current_base = current_base->base_buffer;
- if (window_base->base_buffer)
- window_base = window_base->base_buffer;
- if (current_base == window_base)
- buffer_shared++;
- }
+ if (mode_line_update_needed (w))
+ update_mode_line = 1;
/* Point refers normally to the selected window. For any other
window, set up appropriate value. */
if (!EQ (window, selected_window))
{
- ptrdiff_t new_pt = XMARKER (w->pointm)->charpos;
+ ptrdiff_t new_pt = marker_position (w->pointm);
ptrdiff_t new_pt_byte = marker_byte_position (w->pointm);
if (new_pt < BEGV)
{
Move it back to a fully-visible line. */
new_vpos = window_box_height (w);
}
+ else if (w->cursor.vpos >=0)
+ {
+ /* Some people insist on not letting point enter the scroll
+ margin, even though this part handles windows that didn't
+ scroll at all. */
+ int margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
+ int pixel_margin = margin * FRAME_LINE_HEIGHT (f);
+ bool header_line = WINDOW_WANTS_HEADER_LINE_P (w);
+
+ /* Note: We add an extra FRAME_LINE_HEIGHT, because the loop
+ below, which finds the row to move point to, advances by
+ the Y coordinate of the _next_ row, see the definition of
+ MATRIX_ROW_BOTTOM_Y. */
+ if (w->cursor.vpos < margin + header_line)
+ new_vpos
+ = pixel_margin + (header_line
+ ? CURRENT_HEADER_LINE_HEIGHT (w)
+ : 0) + FRAME_LINE_HEIGHT (f);
+ else
+ {
+ int window_height = window_box_height (w);
+
+ if (header_line)
+ window_height += CURRENT_HEADER_LINE_HEIGHT (w);
+ if (w->cursor.y >= window_height - pixel_margin)
+ new_vpos = window_height - pixel_margin;
+ }
+ }
/* If we need to move point for either of the above reasons,
now actually do it. */
/* If we are highlighting the region, then we just changed
the region, so redisplay to show it. */
- if (!NILP (Vtransient_mark_mode)
- && !NILP (BVAR (current_buffer, mark_active)))
+ if (0 <= markpos_of_region ())
{
clear_glyph_matrix (w->desired_matrix);
if (!try_window (window, startp, 0))
goto try_to_scroll;
default:
- abort ();
+ emacs_abort ();
}
}
/* If current starting point was originally the beginning of a line
&& (CHARPOS (startp) < ZV
/* Avoid starting at end of buffer. */
|| CHARPOS (startp) == BEGV
- || (w->last_modified >= MODIFF
- && w->last_overlay_modified >= OVERLAY_MODIFF)))
+ || !window_outdated (w)))
{
int d1, d2, d3, d4, d5, d6;
break;
default:
- abort ();
+ emacs_abort ();
}
}
|| w->pseudo_window_p)))
{
update_begin (f);
- BLOCK_INPUT;
+ block_input ();
if (draw_window_fringes (w, 1))
x_draw_vertical_border (w);
- UNBLOCK_INPUT;
+ unblock_input ();
update_end (f);
}
#endif /* HAVE_WINDOW_SYSTEM */
return 0;
/* Can't do this if region may have changed. */
- if ((!NILP (Vtransient_mark_mode)
- && !NILP (BVAR (current_buffer, mark_active)))
+ if (0 <= markpos_of_region ()
|| !NILP (w->region_showing)
|| !NILP (Vshow_trailing_whitespace))
return 0;
}
if (row < bottom_row)
{
- struct glyph *glyph = row->glyphs[TEXT_AREA] + w->cursor.hpos;
- struct glyph *end = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
-
- /* Can't use this optimization with bidi-reordered glyph
- rows, unless cursor is already at point. */
+ /* Can't simply scan the row for point with
+ bidi-reordered glyph rows. Let set_cursor_from_row
+ figure out where to put the cursor, and if it fails,
+ give up. */
if (!NILP (BVAR (XBUFFER (w->buffer), bidi_display_reordering)))
{
- if (!(w->cursor.hpos >= 0
- && w->cursor.hpos < row->used[TEXT_AREA]
- && BUFFERP (glyph->object)
- && glyph->charpos == PT))
- return 0;
+ if (!set_cursor_from_row (w, row, w->current_matrix,
+ 0, 0, 0, 0))
+ {
+ clear_glyph_matrix (w->desired_matrix);
+ return 0;
+ }
}
else
- for (; glyph < end
- && (!BUFFERP (glyph->object)
- || glyph->charpos < PT);
- glyph++)
- {
- w->cursor.hpos++;
- w->cursor.x += glyph->pixel_width;
- }
+ {
+ struct glyph *glyph = row->glyphs[TEXT_AREA] + w->cursor.hpos;
+ struct glyph *end = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
+
+ for (; glyph < end
+ && (!BUFFERP (glyph->object)
+ || glyph->charpos < PT);
+ glyph++)
+ {
+ w->cursor.hpos++;
+ w->cursor.x += glyph->pixel_width;
+ }
+ }
}
}
/* Can't use this if highlighting a region because a cursor movement
will do more than just set the cursor. */
- if (!NILP (Vtransient_mark_mode)
- && !NILP (BVAR (current_buffer, mark_active)))
+ if (0 <= markpos_of_region ())
GIVE_UP (9);
/* Likewise if highlighting trailing whitespace. */
if (row)
set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0);
else
- abort ();
+ emacs_abort ();
return 1;
}
}
if (row)
set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0);
else
- abort ();
+ emacs_abort ();
return 2;
}
}
IF_DEBUG (debug_method_add (w, "C"));
}
else
- abort ();
+ emacs_abort ();
IF_DEBUG (debug_end_pos = XFASTINT (w->window_end_pos);
debug_end_vpos = XFASTINT (w->window_end_vpos));
int saved_char_to_display = it->char_to_display;
int saved_x = it->current_x;
int saved_face_id = it->face_id;
+ int saved_box_end = it->end_of_box_run_p;
struct text_pos saved_pos;
Lisp_Object saved_object;
struct face *face;
it->face_id = it->saved_face_id;
face = FACE_FROM_ID (it->f, it->face_id);
it->face_id = FACE_FOR_CHAR (it->f, face, 0, -1, Qnil);
+ /* In R2L rows, we will prepend a stretch glyph that will
+ have the end_of_box_run_p flag set for it, so there's no
+ need for the appended newline glyph to have that flag
+ set. */
+ if (it->glyph_row->reversed_p
+ /* But if the appended newline glyph goes all the way to
+ the end of the row, there will be no stretch glyph,
+ so leave the box flag set. */
+ && saved_x + FRAME_COLUMN_WIDTH (it->f) < it->last_visible_x)
+ it->end_of_box_run_p = 0;
PRODUCE_GLYPHS (it);
it->len = saved_len;
it->c = saved_c;
it->char_to_display = saved_char_to_display;
+ it->end_of_box_run_p = saved_box_end;
return 1;
}
}
struct glyph *g;
int row_width, stretch_ascent, stretch_width;
struct text_pos saved_pos;
- int saved_face_id, saved_avoid_cursor;
+ int saved_face_id, saved_avoid_cursor, saved_box_start;
for (row_width = 0, g = row_start; g < row_end; g++)
row_width += g->pixel_width;
saved_avoid_cursor = it->avoid_cursor_p;
it->avoid_cursor_p = 1;
saved_face_id = it->face_id;
+ saved_box_start = it->start_of_box_run_p;
/* The last row's stretch glyph should get the default
face, to avoid painting the rest of the window with
the region face, if the region ends at ZV. */
it->face_id = default_face->id;
else
it->face_id = face->id;
+ it->start_of_box_run_p = 0;
append_stretch_glyph (it, make_number (0), stretch_width,
it->ascent + it->descent, stretch_ascent);
it->position = saved_pos;
it->avoid_cursor_p = saved_avoid_cursor;
it->face_id = saved_face_id;
+ it->start_of_box_run_p = saved_box_start;
}
}
#endif /* HAVE_WINDOW_SYSTEM */
/* A line that is entirely from a string/image/stretch... */
row->maxpos = row->minpos;
else
- abort ();
+ emacs_abort ();
}
else
row->maxpos = it->current.pos;
return Qright_to_left;
break;
default:
- abort ();
+ emacs_abort ();
}
}
}
this. */
it.paragraph_embedding = L2R;
- if (! mode_line_inverse_video)
- /* Force the menu-bar to be displayed in the default face. */
- it.base_face_id = it.face_id = DEFAULT_FACE_ID;
-
/* Clear all rows of the menu bar. */
for (i = 0; i < FRAME_MENU_BAR_LINES (f); ++i)
{
static int
display_mode_lines (struct window *w)
{
- Lisp_Object old_selected_window, old_selected_frame;
+ Lisp_Object old_selected_window = selected_window;
+ Lisp_Object old_selected_frame = selected_frame;
+ Lisp_Object new_frame = w->frame;
+ Lisp_Object old_frame_selected_window = XFRAME (new_frame)->selected_window;
int n = 0;
- old_selected_frame = selected_frame;
- selected_frame = w->frame;
- old_selected_window = selected_window;
+ selected_frame = new_frame;
+ /* FIXME: If we were to allow the mode-line's computation changing the buffer
+ or window's point, then we'd need select_window_1 here as well. */
XSETWINDOW (selected_window, w);
+ XFRAME (new_frame)->selected_window = selected_window;
/* These will be set while the mode line specs are processed. */
line_number_displayed = 0;
++n;
}
+ XFRAME (new_frame)->selected_window = old_frame_selected_window;
selected_frame = old_selected_frame;
selected_window = old_selected_window;
return n;
it.glyph_row->mode_line_p = 1;
- if (! mode_line_inverse_video)
- /* Force the mode-line to be displayed in the default face. */
- it.base_face_id = it.face_id = DEFAULT_FACE_ID;
-
/* FIXME: This should be controlled by a user option. But
supporting such an option is not trivial, since the mode line is
made up of many separate strings. */
Lisp_Object str;
int string_start = 0;
- if (NILP (window))
- window = selected_window;
- CHECK_WINDOW (window);
- w = XWINDOW (window);
+ w = decode_any_window (window);
+ XSETWINDOW (window, w);
if (NILP (buffer))
buffer = w->buffer;
: EQ (face, Qtool_bar) ? TOOL_BAR_FACE_ID
: DEFAULT_FACE_ID;
- if (XBUFFER (buffer) != current_buffer)
- old_buffer = current_buffer;
+ old_buffer = current_buffer;
/* Save things including mode_line_proptrans_alist,
and set that to nil so that we don't alter the outer value. */
record_unwind_protect (unwind_format_mode_line,
format_mode_line_unwind_data
- (XFRAME (WINDOW_FRAME (XWINDOW (window))),
+ (XFRAME (WINDOW_FRAME (w)),
old_buffer, selected_window, 1));
mode_line_proptrans_alist = Qnil;
Fselect_window (window, Qt);
- if (old_buffer)
- set_buffer_internal_1 (XBUFFER (buffer));
+ set_buffer_internal_1 (XBUFFER (buffer));
init_iterator (&it, w, -1, -1, NULL, face_id);
Lisp_Object obj;
struct frame *f = XFRAME (WINDOW_FRAME (w));
char *decode_mode_spec_buf = f->decode_mode_spec_buffer;
+ /* We are going to use f->decode_mode_spec_buffer as the buffer to
+ produce strings from numerical values, so limit preposterously
+ large values of FIELD_WIDTH to avoid overrunning the buffer's
+ end. The size of the buffer is enough for FRAME_MESSAGE_BUF_SIZE
+ bytes plus the terminating null. */
+ int width = min (field_width, FRAME_MESSAGE_BUF_SIZE (f));
struct buffer *b = current_buffer;
obj = Qnil;
register int i;
/* Let lots_of_dashes be a string of infinite length. */
- if (mode_line_target == MODE_LINE_NOPROP ||
- mode_line_target == MODE_LINE_STRING)
+ if (mode_line_target == MODE_LINE_NOPROP
+ || mode_line_target == MODE_LINE_STRING)
return "--";
if (field_width <= 0
|| field_width > sizeof (lots_of_dashes))
{
ptrdiff_t col = current_column ();
wset_column_number_displayed (w, make_number (col));
- pint2str (decode_mode_spec_buf, field_width, col);
+ pint2str (decode_mode_spec_buf, width, col);
return decode_mode_spec_buf;
}
case 'i':
{
ptrdiff_t size = ZV - BEGV;
- pint2str (decode_mode_spec_buf, field_width, size);
+ pint2str (decode_mode_spec_buf, width, size);
return decode_mode_spec_buf;
}
case 'I':
{
ptrdiff_t size = ZV - BEGV;
- pint2hrstr (decode_mode_spec_buf, field_width, size);
+ pint2hrstr (decode_mode_spec_buf, width, size);
return decode_mode_spec_buf;
}
if (mode_line_target == MODE_LINE_TITLE)
return "";
- startpos = XMARKER (w->start)->charpos;
+ startpos = marker_position (w->start);
startpos_byte = marker_byte_position (w->start);
height = WINDOW_TOTAL_LINES (w);
line_number_displayed = 1;
/* Make the string to show. */
- pint2str (decode_mode_spec_buf, field_width, topline + nlines);
+ pint2str (decode_mode_spec_buf, width, topline + nlines);
return decode_mode_spec_buf;
no_value:
{
char* p = decode_mode_spec_buf;
- int pad = field_width - 2;
+ int pad = width - 2;
while (pad-- > 0)
*p++ = ' ';
*p++ = '?';
{
/* Glyph is off the left margin of the display area.
Should not happen. */
- abort ();
+ emacs_abort ();
}
row->ascent = max (row->ascent, it->max_ascent);
/* Append the list of glyph strings with head H and tail T to the list
with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
-static inline void
+static void
append_glyph_string_lists (struct glyph_string **head, struct glyph_string **tail,
struct glyph_string *h, struct glyph_string *t)
{
list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
result. */
-static inline void
+static void
prepend_glyph_string_lists (struct glyph_string **head, struct glyph_string **tail,
struct glyph_string *h, struct glyph_string *t)
{
/* Append glyph string S to the list with head *HEAD and tail *TAIL.
Set *HEAD and *TAIL to the resulting list. */
-static inline void
+static void
append_glyph_string (struct glyph_string **head, struct glyph_string **tail,
struct glyph_string *s)
{
Value is a pointer to a realized face that is ready for display if
DISPLAY_P is non-zero. */
-static inline struct face *
+static struct face *
get_char_face_and_encoding (struct frame *f, int c, int face_id,
XChar2b *char2b, int display_p)
{
The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
a pointer to a realized face that is ready for display. */
-static inline struct face *
+static struct face *
get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph,
XChar2b *char2b, int *two_byte_p)
{
/* Get glyph code of character C in FONT in the two-byte form CHAR2B.
Return 1 if FONT has a glyph for C, otherwise return 0. */
-static inline int
+static int
get_char_glyph_code (int c, struct font *font, XChar2b *char2b)
{
unsigned code;
{
int x = 0, i;
struct glyph *glyphs = s->row->glyphs[s->area];
- int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
+ int first = (s->first_glyph - glyphs
+ + (s->first_glyph->type == COMPOSITE_GLYPH ? 1 : s->nchars));
int end = s->row->used[s->area];
for (i = first; i < end && s->right_overhang > x; ++i)
int i, k, x;
int end = s->row->used[s->area];
struct glyph *glyphs = s->row->glyphs[s->area];
- int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
+ int first = (s->first_glyph - glyphs
+ + (s->first_glyph->type == COMPOSITE_GLYPH ? 1 : s->nchars));
k = -1;
x = 0;
first glyph following S. LAST_X is the right-most x-position + 1
in the drawing area. */
-static inline void
+static void
set_glyph_string_background_width (struct glyph_string *s, int start, int last_x)
{
/* If the face of this glyph string has to be drawn to the end of
break; \
\
default: \
- abort (); \
+ emacs_abort (); \
} \
\
if (s) \
/* Let's rather be paranoid than getting a SEGV. */
end = min (end, row->used[area]);
- start = max (0, start);
- start = min (end, start);
+ start = clip_to_bounds (0, start, end);
/* Translate X to frame coordinates. Set last_x to the right
end of the drawing area. */
/* If mouse highlighting is on, we may need to draw adjacent
glyphs using mouse-face highlighting. */
- if (area == TEXT_AREA && row->mouse_face_p)
+ if (area == TEXT_AREA && row->mouse_face_p
+ && hlinfo->mouse_face_beg_row >= 0
+ && hlinfo->mouse_face_end_row >= 0)
{
struct glyph_row *mouse_beg_row, *mouse_end_row;
/* Store one glyph for IT->char_to_display in IT->glyph_row.
Called from x_produce_glyphs when IT->glyph_row is non-null. */
-static inline void
+static void
append_glyph (struct it *it)
{
struct glyph *glyph;
glyph->type = CHAR_GLYPH;
glyph->avoid_cursor_p = it->avoid_cursor_p;
glyph->multibyte_p = it->multibyte_p;
- glyph->left_box_line_p = it->start_of_box_run_p;
- glyph->right_box_line_p = it->end_of_box_run_p;
+ if (it->glyph_row->reversed_p && area == TEXT_AREA)
+ {
+ /* In R2L rows, the left and the right box edges need to be
+ drawn in reverse direction. */
+ glyph->right_box_line_p = it->start_of_box_run_p;
+ glyph->left_box_line_p = it->end_of_box_run_p;
+ }
+ else
+ {
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ }
glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
|| it->phys_descent > it->descent);
glyph->glyph_not_available_p = it->glyph_not_available_p;
{
glyph->resolved_level = it->bidi_it.resolved_level;
if ((it->bidi_it.type & 7) != it->bidi_it.type)
- abort ();
+ emacs_abort ();
glyph->bidi_type = it->bidi_it.type;
}
else
IT->glyph_row. Called from x_produce_glyphs when IT->glyph_row is
non-null. */
-static inline void
+static void
append_composite_glyph (struct it *it)
{
struct glyph *glyph;
}
glyph->avoid_cursor_p = it->avoid_cursor_p;
glyph->multibyte_p = it->multibyte_p;
- glyph->left_box_line_p = it->start_of_box_run_p;
- glyph->right_box_line_p = it->end_of_box_run_p;
+ if (it->glyph_row->reversed_p && area == TEXT_AREA)
+ {
+ /* In R2L rows, the left and the right box edges need to be
+ drawn in reverse direction. */
+ glyph->right_box_line_p = it->start_of_box_run_p;
+ glyph->left_box_line_p = it->end_of_box_run_p;
+ }
+ else
+ {
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ }
glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
|| it->phys_descent > it->descent);
glyph->padding_p = 0;
{
glyph->resolved_level = it->bidi_it.resolved_level;
if ((it->bidi_it.type & 7) != it->bidi_it.type)
- abort ();
+ emacs_abort ();
glyph->bidi_type = it->bidi_it.type;
}
++it->glyph_row->used[area];
/* Change IT->ascent and IT->height according to the setting of
IT->voffset. */
-static inline void
+static void
take_vertical_position_into_account (struct it *it)
{
if (it->voffset)
glyph->type = IMAGE_GLYPH;
glyph->avoid_cursor_p = it->avoid_cursor_p;
glyph->multibyte_p = it->multibyte_p;
- glyph->left_box_line_p = it->start_of_box_run_p;
- glyph->right_box_line_p = it->end_of_box_run_p;
+ if (it->glyph_row->reversed_p && area == TEXT_AREA)
+ {
+ /* In R2L rows, the left and the right box edges need to be
+ drawn in reverse direction. */
+ glyph->right_box_line_p = it->start_of_box_run_p;
+ glyph->left_box_line_p = it->end_of_box_run_p;
+ }
+ else
+ {
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ }
glyph->overlaps_vertically_p = 0;
glyph->padding_p = 0;
glyph->glyph_not_available_p = 0;
{
glyph->resolved_level = it->bidi_it.resolved_level;
if ((it->bidi_it.type & 7) != it->bidi_it.type)
- abort ();
+ emacs_abort ();
glyph->bidi_type = it->bidi_it.type;
}
++it->glyph_row->used[area];
glyph->type = STRETCH_GLYPH;
glyph->avoid_cursor_p = it->avoid_cursor_p;
glyph->multibyte_p = it->multibyte_p;
- glyph->left_box_line_p = it->start_of_box_run_p;
- glyph->right_box_line_p = it->end_of_box_run_p;
+ if (it->glyph_row->reversed_p && area == TEXT_AREA)
+ {
+ /* In R2L rows, the left and the right box edges need to be
+ drawn in reverse direction. */
+ glyph->right_box_line_p = it->start_of_box_run_p;
+ glyph->left_box_line_p = it->end_of_box_run_p;
+ }
+ else
+ {
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ }
glyph->overlaps_vertically_p = 0;
glyph->padding_p = 0;
glyph->glyph_not_available_p = 0;
{
glyph->resolved_level = it->bidi_it.resolved_level;
if ((it->bidi_it.type & 7) != it->bidi_it.type)
- abort ();
+ emacs_abort ();
glyph->bidi_type = it->bidi_it.type;
}
else
Lisp_Object prop, plist;
int width = 0, height = 0, align_to = -1;
int zero_width_ok_p = 0;
- int ascent = 0;
double tem;
- struct face *face = NULL;
struct font *font = NULL;
#ifdef HAVE_WINDOW_SYSTEM
+ int ascent = 0;
int zero_height_ok_p = 0;
if (FRAME_WINDOW_P (it->f))
{
- face = FACE_FROM_ID (it->f, it->face_id);
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
font = face->font ? face->font : FRAME_FONT (it->f);
PREPARE_FACE_FOR_DISPLAY (it->f, face);
}
}
}
else
- abort ();
+ emacs_abort ();
#ifdef HAVE_WINDOW_SYSTEM
/* On a GUI frame, when the right fringe (left fringe for R2L rows)
glyph->slice.glyphless.lower_yoff = lower_yoff;
glyph->avoid_cursor_p = it->avoid_cursor_p;
glyph->multibyte_p = it->multibyte_p;
- glyph->left_box_line_p = it->start_of_box_run_p;
- glyph->right_box_line_p = it->end_of_box_run_p;
+ if (it->glyph_row->reversed_p && area == TEXT_AREA)
+ {
+ /* In R2L rows, the left and the right box edges need to be
+ drawn in reverse direction. */
+ glyph->right_box_line_p = it->start_of_box_run_p;
+ glyph->left_box_line_p = it->end_of_box_run_p;
+ }
+ else
+ {
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ }
glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
|| it->phys_descent > it->descent);
glyph->padding_p = 0;
{
glyph->resolved_level = it->bidi_it.resolved_level;
if ((it->bidi_it.type & 7) != it->bidi_it.type)
- abort ();
+ emacs_abort ();
glyph->bidi_type = it->bidi_it.type;
}
++it->glyph_row->used[area];
if (updated_row->reversed_p && chpos >= updated_row->used[TEXT_AREA])
chpos = updated_row->used[TEXT_AREA] - 1;
- BLOCK_INPUT;
+ block_input ();
/* Write glyphs. */
&& chpos < hpos + len)
updated_window->phys_cursor_on_p = 0;
- UNBLOCK_INPUT;
+ unblock_input ();
/* Advance the output cursor. */
output_cursor.hpos += len;
ptrdiff_t hpos;
eassert (updated_window && updated_row);
- BLOCK_INPUT;
+ block_input ();
w = updated_window;
f = XFRAME (WINDOW_FRAME (w));
/* Advance the output cursor. */
output_cursor.hpos += len;
output_cursor.x += shift_by_width;
- UNBLOCK_INPUT;
+ unblock_input ();
}
/* Prevent inadvertently clearing to end of the X window. */
if (to_x > from_x && to_y > from_y)
{
- BLOCK_INPUT;
+ block_input ();
FRAME_RIF (f)->clear_frame_area (f, from_x, from_y,
to_x - from_x, to_y - from_y);
- UNBLOCK_INPUT;
+ unblock_input ();
}
}
{
int i, x;
- BLOCK_INPUT;
+ block_input ();
x = 0;
for (i = 0; i < row->used[area];)
}
}
- UNBLOCK_INPUT;
+ unblock_input ();
}
|| (0 <= hpos && hpos < glyph_row->used[TEXT_AREA]))
glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
- eassert (interrupt_input_blocked);
+ eassert (input_blocked_p ());
/* Set new_cursor_type to the cursor we want to be displayed. */
new_cursor_type = get_window_cursor_type (w, glyph,
if (row->reversed_p && hpos >= row->used[TEXT_AREA])
hpos = row->used[TEXT_AREA] - 1;
- BLOCK_INPUT;
+ block_input ();
display_and_set_cursor (w, on, hpos, vpos,
w->phys_cursor.x, w->phys_cursor.y);
- UNBLOCK_INPUT;
+ unblock_input ();
}
}
if (row->reversed_p && hpos >= row->used[TEXT_AREA])
hpos = row->used[TEXT_AREA] - 1;
- BLOCK_INPUT;
+ block_input ();
display_and_set_cursor (w, 1, hpos, w->phys_cursor.vpos,
w->phys_cursor.x, w->phys_cursor.y);
- UNBLOCK_INPUT;
+ unblock_input ();
}
#endif /* HAVE_WINDOW_SYSTEM */
}
if (hlinfo->mouse_face_defer)
return;
- if (gc_in_progress)
- {
- hlinfo->mouse_face_deferred_gc = 1;
- return;
- }
-
/* Which window is that in? */
window = window_from_coordinates (f, x, y, &part, 1);
Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
Lisp_Object window;
- BLOCK_INPUT;
+ block_input ();
XSETWINDOW (window, w);
if (EQ (window, hlinfo->mouse_face_window))
clear_mouse_face (hlinfo);
- UNBLOCK_INPUT;
+ unblock_input ();
}
staticpro (&Vmessage_stack);
DEFSYM (Qinhibit_redisplay, "inhibit-redisplay");
+ DEFSYM (Qredisplay_internal, "redisplay_internal (C function)");
message_dolog_marker1 = Fmake_marker ();
staticpro (&message_dolog_marker1);
If `word-wrap' is enabled, you might want to reduce this. */);
Vtruncate_partial_width_windows = make_number (50);
- DEFVAR_BOOL ("mode-line-inverse-video", mode_line_inverse_video,
- doc: /* When nil, display the mode-line/header-line/menu-bar in the default face.
-Any other value means to use the appropriate face, `mode-line',
-`header-line', or `menu' respectively. */);
- mode_line_inverse_video = 1;
-
DEFVAR_LISP ("line-number-display-limit", Vline_number_display_limit,
doc: /* Maximum buffer size for which line number should be displayed.
If the buffer is bigger than this, the line number does not appear
doc: /* Maximum number of lines to keep in the message log buffer.
If nil, disable message logging. If t, log messages but don't truncate
the buffer when it becomes large. */);
- Vmessage_log_max = make_number (100);
+ Vmessage_log_max = make_number (1000);
DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_functions,
doc: /* Functions called before redisplay, if window sizes have changed.
Vglyphless_char_display = Fmake_char_table (Qglyphless_char_display, Qnil);
Fset_char_table_extra_slot (Vglyphless_char_display, make_number (0),
Qempty_box);
+
+ DEFVAR_LISP ("debug-on-message", Vdebug_on_message,
+ doc: /* If non-nil, debug if a message matching this regexp is displayed. */);
+ Vdebug_on_message = Qnil;
}
help_echo_showing_p = 0;
}
-/* Since w32 does not support atimers, it defines its own implementation of
- the following three functions in w32fns.c. */
-#ifndef WINDOWSNT
-
-/* Platform-independent portion of hourglass implementation. */
+/* Platform-independent portion of hourglass implementation. */
/* Cancel a currently active hourglass timer, and start a new one. */
void
else
delay = make_emacs_time (DEFAULT_HOURGLASS_DELAY, 0);
+#ifdef HAVE_NTGUI
+ {
+ extern void w32_note_current_window (void);
+ w32_note_current_window ();
+ }
+#endif /* HAVE_NTGUI */
+
hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
show_hourglass, NULL);
#endif
hide_hourglass ();
#endif
}
-#endif /* ! WINDOWSNT */