/* Display generation from window structure and buffer text.
-Copyright (C) 1985-1988, 1993-1995, 1997-2013 Free Software Foundation, Inc.
+Copyright (C) 1985-1988, 1993-1995, 1997-2014 Free Software Foundation,
+Inc.
This file is part of GNU Emacs.
static bool message_enable_multibyte;
-/* Nonzero if we should redraw the mode lines on the next redisplay. */
+/* Nonzero if we should redraw the mode lines on the next redisplay.
+ If it has value REDISPLAY_SOME, then only redisplay the mode lines where
+ the `redisplay' bit has been set. Otherwise, redisplay all mode lines
+ (the number used is then only used to track down the cause for this
+ full-redisplay). */
int update_mode_lines;
-/* Nonzero if window sizes or contents have changed since last
- redisplay that finished. */
+/* Nonzero if window sizes or contents other than selected-window have changed
+ since last redisplay that finished.
+ If it has value REDISPLAY_SOME, then only redisplay the windows where
+ the `redisplay' bit has been set. Otherwise, redisplay all windows
+ (the number used is then only used to track down the cause for this
+ full-redisplay). */
int windows_or_buffers_changed;
CACHE = NULL; \
} while (0)
+/* Functions to mark elements as needing redisplay. */
+enum { REDISPLAY_SOME = 2}; /* Arbitrary choice. */
+
+void
+redisplay_other_windows (void)
+{
+ if (!windows_or_buffers_changed)
+ windows_or_buffers_changed = REDISPLAY_SOME;
+}
+
+void
+wset_redisplay (struct window *w)
+{
+ /* Beware: selected_window can be nil during early stages. */
+ if (!EQ (make_lisp_ptr (w, Lisp_Vectorlike), selected_window))
+ redisplay_other_windows ();
+ w->redisplay = true;
+}
+
+void
+fset_redisplay (struct frame *f)
+{
+ redisplay_other_windows ();
+ f->redisplay = true;
+}
+
+void
+bset_redisplay (struct buffer *b)
+{
+ int count = buffer_window_count (b);
+ if (count > 0)
+ {
+ /* ... it's visible in other window than selected, */
+ if (count > 1 || b != XBUFFER (XWINDOW (selected_window)->contents))
+ redisplay_other_windows ();
+ /* Even if we don't set windows_or_buffers_changed, do set `redisplay'
+ so that if we later set windows_or_buffers_changed, this buffer will
+ not be omitted. */
+ b->text->redisplay = true;
+ }
+}
+
+void
+bset_update_mode_line (struct buffer *b)
+{
+ if (!update_mode_lines)
+ update_mode_lines = REDISPLAY_SOME;
+ b->text->redisplay = true;
+}
+
#ifdef GLYPH_DEBUG
/* Non-zero means print traces of redisplay if compiled with
GLYPH_DEBUG defined. */
-int trace_redisplay_p;
+bool trace_redisplay_p;
#endif /* GLYPH_DEBUG */
static int display_prop_string_p (Lisp_Object, Lisp_Object);
static int row_for_charpos_p (struct glyph_row *, ptrdiff_t);
static int cursor_row_p (struct glyph_row *);
-static int redisplay_mode_lines (Lisp_Object, int);
+static int redisplay_mode_lines (Lisp_Object, bool);
static char *decode_mode_spec_coding (Lisp_Object, char *, int);
static Lisp_Object get_it_property (struct it *it, Lisp_Object prop);
static void redisplay_internal (void);
static int echo_area_display (int);
static void redisplay_windows (Lisp_Object);
-static void redisplay_window (Lisp_Object, int);
+static void redisplay_window (Lisp_Object, bool);
static Lisp_Object redisplay_window_error (Lisp_Object);
static Lisp_Object redisplay_window_0 (Lisp_Object);
static Lisp_Object redisplay_window_1 (Lisp_Object);
static void x_consider_frame_title (Lisp_Object);
static void update_tool_bar (struct frame *, int);
static int redisplay_tool_bar (struct frame *);
+static void x_draw_bottom_divider (struct window *w);
static void notice_overwritten_cursor (struct window *,
enum glyph_row_area,
int, int, int, int);
static void produce_special_glyphs (struct it *, enum display_element_type);
static void show_mouse_face (Mouse_HLInfo *, enum draw_glyphs_face);
-static int coords_in_mouse_face_p (struct window *, int, int);
+static bool coords_in_mouse_face_p (struct window *, int, int);
\f
int
window_text_bottom_y (struct window *w)
{
- int height = WINDOW_TOTAL_HEIGHT (w);
+ int height = WINDOW_PIXEL_HEIGHT (w);
+
+ height -= WINDOW_BOTTOM_DIVIDER_WIDTH (w);
if (WINDOW_WANTS_MODELINE_P (w))
height -= CURRENT_MODE_LINE_HEIGHT (w);
+
return height;
}
int
window_box_width (struct window *w, enum glyph_row_area area)
{
- int cols = w->total_cols;
- int pixels = 0;
+ int pixels = w->pixel_width;
if (!w->pseudo_window_p)
{
- cols -= WINDOW_SCROLL_BAR_COLS (w);
+ pixels -= WINDOW_SCROLL_BAR_AREA_WIDTH (w);
+ pixels -= WINDOW_RIGHT_DIVIDER_WIDTH (w);
if (area == TEXT_AREA)
- {
- cols -= max (0, w->left_margin_cols);
- cols -= max (0, w->right_margin_cols);
- pixels = -WINDOW_TOTAL_FRINGE_WIDTH (w);
- }
+ pixels -= (WINDOW_MARGINS_WIDTH (w)
+ + WINDOW_FRINGES_WIDTH (w));
else if (area == LEFT_MARGIN_AREA)
- {
- cols = max (0, w->left_margin_cols);
- pixels = 0;
- }
+ pixels = WINDOW_LEFT_MARGIN_WIDTH (w);
else if (area == RIGHT_MARGIN_AREA)
- {
- cols = max (0, w->right_margin_cols);
- pixels = 0;
- }
+ pixels = WINDOW_RIGHT_MARGIN_WIDTH (w);
}
- return cols * WINDOW_FRAME_COLUMN_WIDTH (w) + pixels;
+ return pixels;
}
window_box_height (struct window *w)
{
struct frame *f = XFRAME (w->frame);
- int height = WINDOW_TOTAL_HEIGHT (w);
+ int height = WINDOW_PIXEL_HEIGHT (w);
eassert (height >= 0);
+ height -= WINDOW_BOTTOM_DIVIDER_WIDTH (w);
+
/* Note: the code below that determines the mode-line/header-line
height is essentially the same as that contained in the macro
CURRENT_{MODE,HEADER}_LINE_HEIGHT, except that it checks whether
if (top_y < window_top_y)
visible_p = bottom_y > window_top_y;
else if (top_y < it.last_visible_y)
- visible_p = 1;
+ visible_p = true;
if (bottom_y >= it.last_visible_y
&& it.bidi_p && it.bidi_it.scan_dir == -1
&& IT_CHARPOS (it) < charpos)
if (charpos < IT_CHARPOS (it)
|| (it.what == IT_EOB && charpos == IT_CHARPOS (it)))
{
- visible_p = 1;
+ visible_p = true;
RESTORE_IT (&it2, &it2, it2data);
move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
*x = it2.current_x;
FRAME_COLUMN_WIDTH (f) - 1,
FRAME_LINE_HEIGHT (f) - 1);
+ /* PXW: Should we clip pixels before converting to columns/lines? */
if (!noclip)
{
if (pix_x < 0)
{
/* Draw full-width. X coordinates are relative to S->w->left_col. */
r.x = WINDOW_LEFT_EDGE_X (s->w);
- r.width = WINDOW_TOTAL_WIDTH (s->w);
+ if (s->row->mode_line_p)
+ r.width = WINDOW_PIXEL_WIDTH (s->w) - WINDOW_RIGHT_DIVIDER_WIDTH (s->w);
+ else
+ r.width = WINDOW_PIXEL_WIDTH (s->w);
/* Unless displaying a mode or menu bar line, which are always
fully visible, clip to the visible part of the row. */
/* Try to determine frame pixel position and size of the glyph under
frame pixel coordinates X/Y on frame F. */
- if (!f->glyphs_initialized_p
- || (window = window_from_coordinates (f, gx, gy, &part, 0),
- NILP (window)))
+ if (window_resize_pixelwise)
+ {
+ width = height = 1;
+ goto virtual_glyph;
+ }
+ else if (!f->glyphs_initialized_p
+ || (window = window_from_coordinates (f, gx, gy, &part, 0),
+ NILP (window)))
{
width = FRAME_SMALLEST_CHAR_WIDTH (f);
height = FRAME_SMALLEST_FONT_HEIGHT (f);
it->redisplay_end_trigger_charpos
= marker_position (w->redisplay_end_trigger);
else if (INTEGERP (w->redisplay_end_trigger))
- it->redisplay_end_trigger_charpos =
- clip_to_bounds (PTRDIFF_MIN, XINT (w->redisplay_end_trigger), PTRDIFF_MAX);
+ it->redisplay_end_trigger_charpos
+ = clip_to_bounds (PTRDIFF_MIN, XINT (w->redisplay_end_trigger),
+ PTRDIFF_MAX);
it->tab_width = SANE_TAB_WIDTH (current_buffer);
&& ((!NILP (Vtruncate_partial_width_windows)
&& !INTEGERP (Vtruncate_partial_width_windows))
|| (INTEGERP (Vtruncate_partial_width_windows)
+ /* PXW: Shall we do something about this? */
&& (WINDOW_TOTAL_COLS (it->w)
< XINT (Vtruncate_partial_width_windows))))))
it->line_wrap = TRUNCATE;
{
/* Mode lines, menu bar in terminal frames. */
it->first_visible_x = 0;
- it->last_visible_x = WINDOW_TOTAL_WIDTH (w);
+ it->last_visible_x = WINDOW_PIXEL_WIDTH (w);
}
else
{
- it->first_visible_x =
- window_hscroll_limited (it->w, it->f) * FRAME_COLUMN_WIDTH (it->f);
+ it->first_visible_x
+ = window_hscroll_limited (it->w, it->f) * FRAME_COLUMN_WIDTH (it->f);
it->last_visible_x = (it->first_visible_x
+ window_box_width (w, TEXT_AREA));
with a left box line. */
face = FACE_FROM_ID (it->f, remapped_base_face_id);
if (face->box != FACE_NO_BOX)
- it->start_of_box_run_p = 1;
+ it->start_of_box_run_p = true;
}
/* If a buffer position was specified, set the iterator there,
pop_it (it);
else
{
- it->ignore_overlay_strings_at_pos_p = 1;
+ it->ignore_overlay_strings_at_pos_p = true;
it->string_from_display_prop_p = 0;
it->from_disp_prop_p = 0;
handle_overlay_change_p = 0;
prop = Fget_text_property (end_charpos, Qinvisible, it->string);
invis_p = TEXT_PROP_MEANS_INVISIBLE (prop);
if (invis_p == 2)
- display_ellipsis_p = 1;
+ display_ellipsis_p = true;
}
}
while (invis_p && endpos < len);
if (display_ellipsis_p)
- it->ellipsis_p = 1;
+ it->ellipsis_p = true;
if (endpos < len)
{
tem = next_stop;
/* If there are adjacent invisible texts, don't lose the
- second one's ellipsis. */
+ second one's ellipsis. */
if (invis_p == 2)
- display_ellipsis_p = 1;
+ display_ellipsis_p = true;
}
while (invis_p);
if (it->bidi_p)
{
ptrdiff_t bpos = CHAR_TO_BYTE (newpos);
- int on_newline =
- bpos == ZV_BYTE || FETCH_BYTE (bpos) == '\n';
- int after_newline =
- newpos <= BEGV || FETCH_BYTE (bpos - 1) == '\n';
+ int on_newline
+ = bpos == ZV_BYTE || FETCH_BYTE (bpos) == '\n';
+ int after_newline
+ = newpos <= BEGV || FETCH_BYTE (bpos - 1) == '\n';
/* If the invisible text ends on a newline or on a
character after a newline, we can avoid the costly,
it->position.charpos = newpos - 1;
it->position.bytepos = CHAR_TO_BYTE (it->position.charpos);
}
- it->ellipsis_p = 1;
+ it->ellipsis_p = true;
/* Let the ellipsis display before
considering any properties of the following char.
Fixes jasonr@gnu.org 01 Oct 07 bug. */
it->saved_face_id = it->face_id = DEFAULT_FACE_ID;
it->method = GET_FROM_DISPLAY_VECTOR;
- it->ellipsis_p = 1;
+ it->ellipsis_p = true;
}
it->method = GET_FROM_IMAGE;
it->from_overlay = Qnil;
it->face_id = face_id;
- it->from_disp_prop_p = 1;
+ it->from_disp_prop_p = true;
/* Say that we haven't consumed the characters with
`display' property yet. The call to pop_it in
when we are finished with the glyph property value. */
push_it (it, position);
it->from_overlay = overlay;
- it->from_disp_prop_p = 1;
+ it->from_disp_prop_p = true;
if (NILP (location))
it->area = TEXT_AREA;
it->stop_charpos = 0;
it->prev_stop = 0;
it->base_level_stop = 0;
- it->string_from_display_prop_p = 1;
+ it->string_from_display_prop_p = true;
/* Say that we haven't consumed the characters with
`display' property yet. The call to pop_it in
set_iterator_to_next will clean this up. */
processed the overlay strings there already, so that
next_element_from_buffer doesn't try it again. */
if (NILP (it->string) && IT_CHARPOS (*it) >= it->end_charpos)
- it->overlay_strings_at_end_processed_p = 1;
+ it->overlay_strings_at_end_processed_p = true;
}
else
{
if (bidi_it_prev)
*bidi_it_prev = bprev;
}
- *skipped_p = newline_found_p = 1;
+ *skipped_p = newline_found_p = true;
}
else
{
it->bidi_it.string.s = NULL;
it->bidi_it.string.lstring = Qnil;
it->bidi_it.string.bufpos = 0;
+ it->bidi_it.string.from_disp_str = 0;
it->bidi_it.string.unibyte = 0;
it->bidi_it.w = it->w;
}
if (! ASCII_CHAR_P (c) && ! NILP (Vnobreak_char_display))
{
if (c == 0xA0)
- nonascii_space_p = 1;
+ nonascii_space_p = true;
else if (c == 0xAD || c == 0x2010 || c == 0x2011)
- nonascii_hyphen_p = 1;
+ nonascii_hyphen_p = true;
}
/* Translate control characters into `\003' or `^C' form.
if (it->method == GET_FROM_STRING
&& it->current.overlay_string_index >= 0
&& it->n_overlay_strings > 0)
- it->ignore_overlay_strings_at_pos_p = 1;
+ it->ignore_overlay_strings_at_pos_p = true;
it->len = it->dpvec_char_len;
set_iterator_to_next (it, reseat_p);
}
- /* Maybe recheck faces after display vector */
+ /* Maybe recheck faces after display vector. */
if (recheck_faces)
it->stop_charpos = IT_CHARPOS (*it);
}
else
{
/* Not an overlay string. There could be padding, so test
- against it->end_charpos . */
+ against it->end_charpos. */
if (IT_STRING_CHARPOS (*it) >= it->end_charpos)
goto consider_string_end;
}
static int
next_element_from_c_string (struct it *it)
{
- int success_p = 1;
+ bool success_p = true;
eassert (it->s);
eassert (!it->bidi_p || it->s == it->bidi_it.string.s);
it->method = GET_FROM_BUFFER;
it->object = it->w->contents;
reseat_at_next_visible_line_start (it, 1);
- it->face_before_selective_p = 1;
+ it->face_before_selective_p = true;
}
return GET_NEXT_DISPLAY_ELEMENT (it);
it->prev_stop = it->stop_charpos;
else
it->prev_stop = BEGV;
- it->bidi_p = 1;
+ it->bidi_p = true;
it->current = save_current;
it->position = save_position;
it->stop_charpos = save_stop_pos;
}
while (charpos <= where_we_are);
- it->bidi_p = 1;
+ it->bidi_p = true;
it->current = save_current;
it->position = save_position;
next_stop = it->stop_charpos;
static int
next_element_from_buffer (struct it *it)
{
- int success_p = 1;
+ bool success_p = true;
eassert (IT_CHARPOS (*it) >= BEGV);
eassert (NILP (it->string) && !it->s);
overlay_strings_follow_p = 0;
else
{
- it->overlay_strings_at_end_processed_p = 1;
+ it->overlay_strings_at_end_processed_p = true;
overlay_strings_follow_p = get_overlay_strings (it, 0);
}
If TO_CHARPOS is in invisible text, e.g. a truncated part of a
screen line, this function will set IT to the next position that is
- displayed to the right of TO_CHARPOS on the screen. */
+ displayed to the right of TO_CHARPOS on the screen.
-void
+ Return the maximum pixel length of any line scanned but never more
+ than it.last_visible_x. */
+
+int
move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos, int op)
{
enum move_it_result skip, skip2 = MOVE_X_REACHED;
int line_height, line_start_x = 0, reached = 0;
+ int max_current_x = 0;
void *backup_data = NULL;
for (;;)
if (to_y >= it->current_y
&& to_y < it->current_y + line_height)
{
+ if (to_y > it->current_y)
+ max_current_x = max (it->current_x, max_current_x);
+
/* When word-wrap is on, TO_X may lie past the end
of a wrapped line. Then it->current is the
character on the next line, so backtrack to the
skip = move_it_in_display_line_to
(it, -1, prev_x, MOVE_TO_X);
}
+
reached = 6;
}
}
if (reached)
- break;
+ {
+ max_current_x = max (it->current_x, max_current_x);
+ break;
+ }
}
else if (BUFFERP (it->object)
&& (it->method == GET_FROM_BUFFER
switch (skip)
{
case MOVE_POS_MATCH_OR_ZV:
+ max_current_x = max (it->current_x, max_current_x);
reached = 8;
goto out;
case MOVE_NEWLINE_OR_CR:
+ max_current_x = max (it->current_x, max_current_x);
set_iterator_to_next (it, 1);
it->continuation_lines_width = 0;
break;
case MOVE_LINE_TRUNCATED:
+ max_current_x = it->last_visible_x;
it->continuation_lines_width = 0;
reseat_at_next_visible_line_start (it, 0);
if ((op & MOVE_TO_POS) != 0
break;
case MOVE_LINE_CONTINUED:
+ max_current_x = it->last_visible_x;
/* For continued lines ending in a tab, some of the glyphs
associated with the tab are displayed on the current
line. Since it->current_x does not include these glyphs,
bidi_unshelve_cache (backup_data, 1);
TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached));
+
+ return max_current_x;
}
}
}
-/* Return 1 if IT points into the middle of a display vector. */
+/* Return true if IT points into the middle of a display vector. */
-int
+bool
in_display_vector_p (struct it *it)
{
return (it->method == GET_FROM_DISPLAY_VECTOR
&& it->dpvec + it->current.dpvec_index != it->dpend);
}
+DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, Swindow_text_pixel_size, 0, 6, 0,
+ doc: /* Return the size of the text of WINDOW's buffer in pixels.
+WINDOW must be a live window and defaults to the selected one. The
+return value is a cons of the maximum pixel-width of any text line and
+the maximum pixel-height of all text lines.
+
+The optional argument FROM, if non-nil, specifies the first text
+position and defaults to the minimum accessible position of the buffer.
+If FROM is t, use the minimum accessible position that is not a newline
+character. TO, if non-nil, specifies the last text position and
+defaults to the maximum accessible position of the buffer. If TO is t,
+use the maximum accessible position that is not a newline character.
+
+The optional argument X_LIMIT, if non-nil, specifies the maximum text
+width that can be returned. X_LIMIT nil or omitted, means to use the
+pixel-width of WINDOW's body; use this if you do not intend to change
+the width of WINDOW. Use the maximum width WINDOW may assume if you
+intend to change WINDOW's width.
+
+The optional argument Y_LIMIT, if non-nil, specifies the maximum text
+height that can be returned. Text lines whose y-coordinate is beyond
+Y_LIMIT are ignored. Since calculating the text height of a large
+buffer can take some time, it makes sense to specify this argument if
+the size of the buffer is unknown.
+
+Optional argument MODE_AND_HEADER_LINE nil or omitted means do not
+include the height of the mode- or header-line of WINDOW in the return
+value. If it is either the symbol `mode-line' or `header-line', include
+only the height of that line, if present, in the return value. If t,
+include the height of both, if present, in the return value. */)
+ (Lisp_Object window, Lisp_Object from, Lisp_Object to, Lisp_Object x_limit, Lisp_Object y_limit,
+ Lisp_Object mode_and_header_line)
+{
+ struct window *w = decode_live_window (window);
+ Lisp_Object buf;
+ struct buffer *b;
+ struct it it;
+ struct buffer *old_buffer = NULL;
+ ptrdiff_t start, end, pos;
+ struct text_pos startp;
+ void *itdata = NULL;
+ int c, max_y = -1, x = 0, y = 0;
+
+ buf = w->contents;
+ CHECK_BUFFER (buf);
+ b = XBUFFER (buf);
+
+ if (b != current_buffer)
+ {
+ old_buffer = current_buffer;
+ set_buffer_internal (b);
+ }
+
+ if (NILP (from))
+ start = BEGV;
+ else if (EQ (from, Qt))
+ {
+ start = pos = BEGV;
+ while ((pos++ < ZV) && (c = FETCH_CHAR (pos))
+ && (c == ' ' || c == '\t' || c == '\n' || c == '\r'))
+ start = pos;
+ while ((pos-- > BEGV) && (c = FETCH_CHAR (pos)) && (c == ' ' || c == '\t'))
+ start = pos;
+ }
+ else
+ {
+ CHECK_NUMBER_COERCE_MARKER (from);
+ start = min (max (XINT (from), BEGV), ZV);
+ }
+
+ if (NILP (to))
+ end = ZV;
+ else if (EQ (to, Qt))
+ {
+ end = pos = ZV;
+ while ((pos-- > BEGV) && (c = FETCH_CHAR (pos))
+ && (c == ' ' || c == '\t' || c == '\n' || c == '\r'))
+ end = pos;
+ while ((pos++ < ZV) && (c = FETCH_CHAR (pos)) && (c == ' ' || c == '\t'))
+ end = pos;
+ }
+ else
+ {
+ CHECK_NUMBER_COERCE_MARKER (to);
+ end = max (start, min (XINT (to), ZV));
+ }
+
+ if (!NILP (y_limit))
+ {
+ CHECK_NUMBER (y_limit);
+ max_y = min (XINT (y_limit), INT_MAX);
+ }
+
+ itdata = bidi_shelve_cache ();
+ SET_TEXT_POS (startp, start, CHAR_TO_BYTE (start));
+ start_display (&it, w, startp);
+
+ if (NILP (x_limit))
+ x = move_it_to (&it, end, -1, max_y, -1, MOVE_TO_POS | MOVE_TO_Y);
+ else
+ {
+ CHECK_NUMBER (x_limit);
+ it.last_visible_x = min (XINT (x_limit), INFINITY);
+ /* Actually, we never want move_it_to stop at to_x. But to make
+ sure that move_it_in_display_line_to always moves far enough,
+ we set it to INT_MAX and specify MOVE_TO_X. */
+ x = move_it_to (&it, end, INT_MAX, max_y, -1,
+ MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+ }
+
+ y = it.current_y + it.max_ascent + it.max_descent;
+
+ if (!EQ (mode_and_header_line, Qheader_line)
+ && !EQ (mode_and_header_line, Qt))
+ /* Do not count the header-line which was counted automatically by
+ start_display. */
+ y = y - WINDOW_HEADER_LINE_HEIGHT (w);
+
+ if (EQ (mode_and_header_line, Qmode_line)
+ || EQ (mode_and_header_line, Qt))
+ /* Do count the mode-line which is not included automatically by
+ start_display. */
+ y = y + WINDOW_MODE_LINE_HEIGHT (w);
+
+ bidi_unshelve_cache (itdata, 0);
+
+ if (old_buffer)
+ set_buffer_internal (old_buffer);
+
+ return Fcons (make_number (x), make_number (y));
+}
\f
/***********************************************************************
Messages
ptrdiff_t point_at_end = 0;
ptrdiff_t zv_at_end = 0;
Lisp_Object old_deactivate_mark;
- bool shown;
struct gcpro gcpro1;
old_deactivate_mark = Vdeactivate_mark;
Fset_buffer (Fget_buffer_create (Vmessages_buffer_name));
- if (newbuffer &&
- !NILP (Ffboundp (intern ("messages-buffer-mode"))))
+ if (newbuffer
+ && !NILP (Ffboundp (intern ("messages-buffer-mode"))))
call0 (intern ("messages-buffer-mode"));
}
bset_undo_list (current_buffer, Qt);
+ bset_cache_long_scans (current_buffer, Qnil);
oldpoint = message_dolog_marker1;
set_marker_restricted_both (oldpoint, Qnil, PT, PT_BYTE);
unchain_marker (XMARKER (oldbegv));
unchain_marker (XMARKER (oldzv));
- shown = buffer_window_count (current_buffer) > 0;
- set_buffer_internal (oldbuf);
/* We called insert_1_both above with its 5th argument (PREPARE)
zero, which prevents insert_1_both from calling
prepare_to_modify_buffer, which in turns prevents us from
incrementing windows_or_buffers_changed even if *Messages* is
- shown in some window. So we must manually incrementing
+ shown in some window. So we must manually set
windows_or_buffers_changed here to make up for that. */
- if (shown)
- windows_or_buffers_changed = 41;
- else
- windows_or_buffers_changed = old_windows_or_buffers_changed;
+ windows_or_buffers_changed = old_windows_or_buffers_changed;
+ bset_redisplay (current_buffer);
+
+ set_buffer_internal (oldbuf);
+
message_log_need_newline = !nlflag;
Vdeactivate_mark = old_deactivate_mark;
}
struct gcpro gcpro1;
GCPRO1 (m);
- clear_message (1,1);
+ clear_message (true, true);
cancel_echoing ();
/* First flush out any partial line written with print. */
echo_message_buffer = Qnil;
}
else
- clear_message (1, 1);
+ clear_message (true, true);
do_pending_window_change (0);
echo_area_display (1);
else
{
this_one = 0, the_other = 1;
- clear_buffer_p = 1;
+ clear_buffer_p = true;
/* We need a fresh one in case the current echo buffer equals
the one containing the last displayed echo area message. */
= (EQ (echo_area_buffer[the_other], echo_buffer[this_one])
? echo_buffer[the_other]
: echo_buffer[this_one]);
- clear_buffer_p = 1;
+ clear_buffer_p = true;
}
buffer = echo_area_buffer[this_one];
&& WINDOWP (echo_area_window))
{
struct window *w = XWINDOW (echo_area_window);
- int resized_p;
- Lisp_Object resize_exactly;
-
- if (minibuf_level == 0)
- resize_exactly = Qt;
- else
- resize_exactly = Qnil;
-
- resized_p = with_echo_area_buffer (w, 0, resize_mini_window_1,
+ Lisp_Object resize_exactly = (minibuf_level == 0 ? Qt : Qnil);
+ int resized_p = with_echo_area_buffer (w, 0, resize_mini_window_1,
(intptr_t) w, resize_exactly);
if (resized_p)
{
if (!FRAME_MINIBUF_ONLY_P (f))
{
struct it it;
- struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
- int total_height = WINDOW_TOTAL_LINES (root) + WINDOW_TOTAL_LINES (w);
- int height;
- EMACS_INT max_height;
+ int total_height = (WINDOW_PIXEL_HEIGHT (XWINDOW (FRAME_ROOT_WINDOW (f)))
+ + WINDOW_PIXEL_HEIGHT (w));
int unit = FRAME_LINE_HEIGHT (f);
+ int height, max_height;
struct text_pos start;
struct buffer *old_current_buffer = NULL;
/* Compute the max. number of lines specified by the user. */
if (FLOATP (Vmax_mini_window_height))
- max_height = XFLOATINT (Vmax_mini_window_height) * FRAME_LINES (f);
+ max_height = XFLOATINT (Vmax_mini_window_height) * total_height;
else if (INTEGERP (Vmax_mini_window_height))
- max_height = XINT (Vmax_mini_window_height);
+ max_height = XINT (Vmax_mini_window_height) * unit;
else
max_height = total_height / 4;
/* Correct that max. height if it's bogus. */
- max_height = clip_to_bounds (1, max_height, total_height);
+ max_height = clip_to_bounds (unit, max_height, total_height);
/* Find out the height of the text in the window. */
if (it.line_wrap == TRUNCATE)
- height = 1;
+ height = unit;
else
{
last_height = 0;
else
height = it.current_y + it.max_ascent + it.max_descent;
height -= min (it.extra_line_spacing, it.max_extra_line_spacing);
- height = (height + unit - 1) / unit;
}
/* Compute a suitable window start. */
if (height > max_height)
{
- height = max_height;
+ height = (max_height / unit) * unit;
init_iterator (&it, w, ZV, ZV_BYTE, NULL, DEFAULT_FACE_ID);
- move_it_vertically_backward (&it, (height - 1) * unit);
+ move_it_vertically_backward (&it, height - unit);
start = it.current.pos;
}
else
{
/* Let it grow only, until we display an empty message, in which
case the window shrinks again. */
- if (height > WINDOW_TOTAL_LINES (w))
+ if (height > WINDOW_PIXEL_HEIGHT (w))
{
- int old_height = WINDOW_TOTAL_LINES (w);
+ int old_height = WINDOW_PIXEL_HEIGHT (w);
FRAME_WINDOWS_FROZEN (f) = 1;
- grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
- window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
+ grow_mini_window (w, height - WINDOW_PIXEL_HEIGHT (w), 1);
+ window_height_changed_p = WINDOW_PIXEL_HEIGHT (w) != old_height;
}
- else if (height < WINDOW_TOTAL_LINES (w)
+ else if (height < WINDOW_PIXEL_HEIGHT (w)
&& (exact_p || BEGV == ZV))
{
- int old_height = WINDOW_TOTAL_LINES (w);
+ int old_height = WINDOW_PIXEL_HEIGHT (w);
FRAME_WINDOWS_FROZEN (f) = 0;
- shrink_mini_window (w);
- window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
+ shrink_mini_window (w, 1);
+ window_height_changed_p = WINDOW_PIXEL_HEIGHT (w) != old_height;
}
}
else
{
/* Always resize to exact size needed. */
- if (height > WINDOW_TOTAL_LINES (w))
+ if (height > WINDOW_PIXEL_HEIGHT (w))
{
- int old_height = WINDOW_TOTAL_LINES (w);
+ int old_height = WINDOW_PIXEL_HEIGHT (w);
FRAME_WINDOWS_FROZEN (f) = 1;
- grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
- window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
+ grow_mini_window (w, height - WINDOW_PIXEL_HEIGHT (w), 1);
+ window_height_changed_p = WINDOW_PIXEL_HEIGHT (w) != old_height;
}
- else if (height < WINDOW_TOTAL_LINES (w))
+ else if (height < WINDOW_PIXEL_HEIGHT (w))
{
- int old_height = WINDOW_TOTAL_LINES (w);
+ int old_height = WINDOW_PIXEL_HEIGHT (w);
FRAME_WINDOWS_FROZEN (f) = 0;
- shrink_mini_window (w);
+ shrink_mini_window (w, 1);
if (height)
{
FRAME_WINDOWS_FROZEN (f) = 1;
- grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
+ grow_mini_window (w, height - WINDOW_PIXEL_HEIGHT (w), 1);
}
- window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
+ window_height_changed_p = WINDOW_PIXEL_HEIGHT (w) != old_height;
}
}
last displayed. */
void
-clear_message (int current_p, int last_displayed_p)
+clear_message (bool current_p, bool last_displayed_p)
{
if (current_p)
{
echo_area_buffer[0] = Qnil;
- message_cleared_p = 1;
+ message_cleared_p = true;
}
if (last_displayed_p)
if (frame_garbaged)
{
Lisp_Object tail, frame;
- int changed_count = 0;
FOR_EACH_FRAME (tail, frame)
{
redraw_frame (f);
else
clear_current_matrices (f);
- changed_count++;
- f->garbaged = 0;
- f->resized_p = 0;
+ fset_redisplay (f);
+ f->garbaged = false;
+ f->resized_p = false;
}
}
- frame_garbaged = 0;
- if (changed_count)
- windows_or_buffers_changed = 43;
+ frame_garbaged = false;
}
}
{
echo_area_window = mini_window;
window_height_changed_p = display_echo_area (w);
- w->must_be_updated_p = 1;
+ w->must_be_updated_p = true;
/* Update the display, unless called from redisplay_internal.
Also don't update the screen during redisplay itself. The
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);
+ n = redisplay_mode_lines (FRAME_ROOT_WINDOW (f), false);
if (window_height_changed_p
/* Don't do this if Emacs is shutting down. Redisplay
redisplay displays the minibuffer, so that the cursor will
be replaced with what the minibuffer wants. */
if (cursor_in_echo_area)
- windows_or_buffers_changed = 45;
+ wset_redisplay (XWINDOW (mini_window));
}
}
else if (!EQ (mini_window, selected_window))
- windows_or_buffers_changed = 46;
+ wset_redisplay (XWINDOW (mini_window));
/* Last displayed message is now the current message. */
echo_area_buffer[1] = echo_area_buffer[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's buffer was changed but not saved. */
static int
Menu Bars
***********************************************************************/
+/* Non-zero if we will not redisplay all visible windows. */
+#define REDISPLAY_SOME_P() \
+ ((windows_or_buffers_changed == 0 \
+ || windows_or_buffers_changed == REDISPLAY_SOME) \
+ && (update_mode_lines == 0 \
+ || update_mode_lines == REDISPLAY_SOME))
/* Prepare for redisplay by updating menu-bar item lists when
appropriate. This can call eval. */
static void
prepare_menu_bars (void)
{
- int all_windows;
+ bool all_windows = windows_or_buffers_changed || update_mode_lines;
+ bool some_windows = REDISPLAY_SOME_P ();
struct gcpro gcpro1, gcpro2;
- struct frame *f;
Lisp_Object tooltip_frame;
#ifdef HAVE_WINDOW_SYSTEM
tooltip_frame = Qnil;
#endif
+ if (FUNCTIONP (Vpre_redisplay_function))
+ {
+ Lisp_Object windows = all_windows ? Qt : Qnil;
+ if (all_windows && some_windows)
+ {
+ Lisp_Object ws = window_list ();
+ for (windows = Qnil; CONSP (ws); ws = XCDR (ws))
+ {
+ Lisp_Object this = XCAR (ws);
+ struct window *w = XWINDOW (this);
+ if (w->redisplay
+ || XFRAME (w->frame)->redisplay
+ || XBUFFER (w->contents)->text->redisplay)
+ {
+ windows = Fcons (this, windows);
+ }
+ }
+ }
+ safe_call1 (Vpre_redisplay_function, windows);
+ }
+
/* Update all frame titles based on their buffer names, etc. We do
this before the menu bars so that the buffer-menu will show the
up-to-date frame titles. */
#ifdef HAVE_WINDOW_SYSTEM
- if (windows_or_buffers_changed || update_mode_lines)
+ if (all_windows)
{
Lisp_Object tail, frame;
FOR_EACH_FRAME (tail, frame)
{
- f = XFRAME (frame);
+ struct frame *f = XFRAME (frame);
+ struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
+ if (some_windows
+ && !f->redisplay
+ && !w->redisplay
+ && !XBUFFER (w->contents)->text->redisplay)
+ continue;
+
if (!EQ (frame, tooltip_frame)
&& (FRAME_ICONIFIED_P (f)
|| FRAME_VISIBLE_P (f) == 1
/* 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_and_changed ()
- || windows_or_buffers_changed);
-
- if (FUNCTIONP (Vpre_redisplay_function))
- safe_call1 (Vpre_redisplay_function, all_windows ? Qt : Qnil);
if (all_windows)
{
FOR_EACH_FRAME (tail, frame)
{
- f = XFRAME (frame);
+ struct frame *f = XFRAME (frame);
+ struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
/* Ignore tooltip frame. */
if (EQ (frame, tooltip_frame))
continue;
+ if (some_windows
+ && !f->redisplay
+ && !w->redisplay
+ && !XBUFFER (w->contents)->text->redisplay)
+ continue;
+
/* If a window on this frame changed size, report that to
the user and clear the size-change flag. */
if (FRAME_WINDOW_SIZES_CHANGED (f))
#if defined (USE_GTK) || defined (HAVE_NS)
int do_update = FRAME_EXTERNAL_TOOL_BAR (f);
#else
- int do_update = WINDOWP (f->tool_bar_window)
- && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0;
+ int do_update = (WINDOWP (f->tool_bar_window)
+ && WINDOW_PIXEL_HEIGHT (XWINDOW (f->tool_bar_window)) > 0);
#endif
if (do_update)
int max_x = it->last_visible_x;
struct glyph *last;
- prepare_desired_row (row);
+ /* Don't extend on a previously drawn tool bar items (Bug#16058). */
+ clear_glyph_row (row);
+ row->enabled_p = true;
row->y = it->current_y;
/* Note that this isn't made use of if the face hasn't a box,
}
-/* Max tool-bar height. */
+/* Max tool-bar height. Basically, this is what makes all other windows
+ disappear when the frame gets too small. Rethink this! */
#define MAX_FRAME_TOOL_BAR_HEIGHT(f) \
((FRAME_LINE_HEIGHT (f) * FRAME_LINES (f)))
-/* Value is the number of screen lines needed to make all tool-bar
- items of frame F visible. The number of actual rows needed is
+/* Value is the number of pixels needed to make all tool-bar items of
+ frame F visible. The actual number of glyph rows needed is
returned in *N_ROWS if non-NULL. */
static int
-tool_bar_lines_needed (struct frame *f, int *n_rows)
+tool_bar_height (struct frame *f, int *n_rows, bool pixelwise)
{
struct window *w = XWINDOW (f->tool_bar_window);
struct it it;
- /* tool_bar_lines_needed is called from redisplay_tool_bar after building
+ /* tool_bar_height is called from redisplay_tool_bar after building
the desired matrix, so use (unused) mode-line row as temporary row to
avoid destroying the first tool-bar row. */
struct glyph_row *temp_row = MATRIX_MODE_LINE_ROW (w->desired_matrix);
F->desired_tool_bar_string in the tool-bar window of frame F. */
init_iterator (&it, w, -1, -1, temp_row, TOOL_BAR_FACE_ID);
it.first_visible_x = 0;
- it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+ it.last_visible_x = WINDOW_PIXEL_WIDTH (w);
reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
it.paragraph_embedding = L2R;
if (n_rows)
*n_rows = it.vpos > 0 ? it.vpos : -1;
- return (it.current_y + FRAME_LINE_HEIGHT (f) - 1) / FRAME_LINE_HEIGHT (f);
+ if (pixelwise)
+ return it.current_y;
+ else
+ return (it.current_y + FRAME_LINE_HEIGHT (f) - 1) / FRAME_LINE_HEIGHT (f);
}
#endif /* !USE_GTK && !HAVE_NS */
#if defined USE_GTK || defined HAVE_NS
+EXFUN (Ftool_bar_height, 2) ATTRIBUTE_CONST;
EXFUN (Ftool_bar_lines_needed, 1) ATTRIBUTE_CONST;
#endif
-DEFUN ("tool-bar-lines-needed", Ftool_bar_lines_needed, Stool_bar_lines_needed,
- 0, 1, 0,
+DEFUN ("tool-bar-height", Ftool_bar_height, Stool_bar_height,
+ 0, 2, 0,
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)
+If FRAME is nil or omitted, use the selected frame. Optional argument
+PIXELWISE non-nil means return the height of the tool bar in pixels. */)
+ (Lisp_Object frame, Lisp_Object pixelwise)
{
- int nlines = 0;
+ int height = 0;
+
#if ! defined (USE_GTK) && ! defined (HAVE_NS)
struct frame *f = decode_any_frame (frame);
- struct window *w;
if (WINDOWP (f->tool_bar_window)
- && (w = XWINDOW (f->tool_bar_window),
- WINDOW_TOTAL_LINES (w) > 0))
+ && WINDOW_PIXEL_HEIGHT (XWINDOW (f->tool_bar_window)) > 0)
{
update_tool_bar (f, 1);
if (f->n_tool_bar_items)
{
build_desired_tool_bar_string (f);
- nlines = tool_bar_lines_needed (f, NULL);
+ height = tool_bar_height (f, NULL, NILP (pixelwise) ? 0 : 1);
}
}
#endif
- return make_number (nlines);
+
+ return make_number (height);
}
can turn off tool-bars by specifying tool-bar-lines zero. */
if (!WINDOWP (f->tool_bar_window)
|| (w = XWINDOW (f->tool_bar_window),
- WINDOW_TOTAL_LINES (w) == 0))
+ WINDOW_PIXEL_HEIGHT (w) == 0))
return 0;
/* Set up an iterator for the tool-bar window. */
init_iterator (&it, w, -1, -1, w->desired_matrix->rows, TOOL_BAR_FACE_ID);
it.first_visible_x = 0;
- it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+ it.last_visible_x = WINDOW_PIXEL_WIDTH (w);
row = it.glyph_row;
/* Build a string that represents the contents of the tool-bar. */
if (f->n_tool_bar_rows == 0)
{
- int nlines;
+ int new_height = tool_bar_height (f, &f->n_tool_bar_rows, 1);
- if ((nlines = tool_bar_lines_needed (f, &f->n_tool_bar_rows),
- nlines != WINDOW_TOTAL_LINES (w)))
+ if (new_height != WINDOW_PIXEL_HEIGHT (w))
{
Lisp_Object frame;
- int old_height = WINDOW_TOTAL_LINES (w);
+ int new_lines = ((new_height + FRAME_LINE_HEIGHT (f) - 1)
+ / FRAME_LINE_HEIGHT (f));
XSETFRAME (frame, f);
Fmodify_frame_parameters (frame,
list1 (Fcons (Qtool_bar_lines,
- make_number (nlines))));
- if (WINDOW_TOTAL_LINES (w) != old_height)
- {
- clear_glyph_matrix (w->desired_matrix);
- f->fonts_changed = 1;
- return 1;
- }
+ make_number (new_lines))));
+ /* Always do that now. */
+ clear_glyph_matrix (w->desired_matrix);
+ f->fonts_changed = 1;
+ return 1;
}
}
if (!NILP (Vauto_resize_tool_bars))
{
+ /* Do we really allow the toolbar to occupy the whole frame? */
int max_tool_bar_height = MAX_FRAME_TOOL_BAR_HEIGHT (f);
int change_height_p = 0;
&& it.current_y < max_tool_bar_height)
change_height_p = 1;
+ /* We subtract 1 because display_tool_bar_line advances the
+ glyph_row pointer before returning to its caller. We want to
+ examine the last glyph row produced by
+ display_tool_bar_line. */
row = it.glyph_row - 1;
/* If there are blank lines at the end, except for a partially
if (change_height_p)
{
Lisp_Object frame;
- int old_height = WINDOW_TOTAL_LINES (w);
int nrows;
- int nlines = tool_bar_lines_needed (f, &nrows);
+ int new_height = tool_bar_height (f, &nrows, 1);
change_height_p = ((EQ (Vauto_resize_tool_bars, Qgrow_only)
&& !f->minimize_tool_bar_window_p)
- ? (nlines > old_height)
- : (nlines != old_height));
+ ? (new_height > WINDOW_PIXEL_HEIGHT (w))
+ : (new_height != WINDOW_PIXEL_HEIGHT (w)));
f->minimize_tool_bar_window_p = 0;
if (change_height_p)
{
- XSETFRAME (frame, f);
- Fmodify_frame_parameters (frame,
- list1 (Fcons (Qtool_bar_lines,
- make_number (nlines))));
- if (WINDOW_TOTAL_LINES (w) != old_height)
+ /* Current size of the tool-bar window in canonical line
+ units. */
+ int old_lines = WINDOW_TOTAL_LINES (w);
+ /* Required size of the tool-bar window in canonical
+ line units. */
+ int new_lines = ((new_height + FRAME_LINE_HEIGHT (f) - 1)
+ / FRAME_LINE_HEIGHT (f));
+ /* Maximum size of the tool-bar window in canonical line
+ units that this frame can allow. */
+ int max_lines =
+ WINDOW_TOTAL_LINES (XWINDOW (FRAME_ROOT_WINDOW (f))) - 1;
+
+ /* Don't try to change the tool-bar window size and set
+ the fonts_changed flag unless really necessary. That
+ flag causes redisplay to give up and retry
+ redisplaying the frame from scratch, so setting it
+ unnecessarily can lead to nasty redisplay loops. */
+ if (new_lines <= max_lines
+ && eabs (new_lines - old_lines) >= 1)
{
+ XSETFRAME (frame, f);
+ Fmodify_frame_parameters (frame,
+ list1 (Fcons (Qtool_bar_lines,
+ make_number (new_lines))));
clear_glyph_matrix (w->desired_matrix);
f->n_tool_bar_rows = nrows;
f->fonts_changed = 1;
{
int h_margin;
int text_area_width;
- struct glyph_row *current_cursor_row
- = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
- struct glyph_row *desired_cursor_row
- = MATRIX_ROW (w->desired_matrix, w->cursor.vpos);
- struct glyph_row *cursor_row
- = (desired_cursor_row->enabled_p
- ? desired_cursor_row
- : current_cursor_row);
- int row_r2l_p = cursor_row->reversed_p;
+ struct glyph_row *cursor_row;
+ struct glyph_row *bottom_row;
+ int row_r2l_p;
+
+ bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->desired_matrix, w);
+ if (w->cursor.vpos < bottom_row - w->desired_matrix->rows)
+ cursor_row = MATRIX_ROW (w->desired_matrix, w->cursor.vpos);
+ else
+ cursor_row = bottom_row - 1;
+
+ if (!cursor_row->enabled_p)
+ {
+ bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
+ if (w->cursor.vpos < bottom_row - w->current_matrix->rows)
+ cursor_row = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
+ else
+ cursor_row = bottom_row - 1;
+ }
+ row_r2l_p = cursor_row->reversed_p;
text_area_width = window_box_width (w, TEXT_AREA);
/* For left-to-right rows, hscroll when cursor is either
(i) inside the right hscroll margin, or (ii) if it is
inside the left margin and the window is already
- hscrolled. */
+ hscrolled. */
&& ((!row_r2l_p
&& ((w->hscroll
&& w->cursor.x <= h_margin)
&& ((cursor_row->enabled_p
/* FIXME: It is confusing to set the
truncated_on_right_p flag when R2L rows
- are actually truncated on the left. */
+ are actually truncated on the left. */
&& cursor_row->truncated_on_right_p
&& w->cursor.x <= h_margin)
|| (w->hscroll
static ptrdiff_t debug_end_vpos;
/* Append a string to W->desired_matrix->method. FMT is a printf
- format string. If trace_redisplay_p is non-zero also printf the
+ format string. If trace_redisplay_p is true also printf the
resulting string to stderr. */
static void debug_method_add (struct window *, char const *, ...)
}
}
+static void
+propagate_buffer_redisplay (void)
+{ /* Resetting b->text->redisplay is problematic!
+ We can't just reset it in the case that some window that displays
+ it has not been redisplayed; and such a window can stay
+ unredisplayed for a long time if it's currently invisible.
+ But we do want to reset it at the end of redisplay otherwise
+ its displayed windows will keep being redisplayed over and over
+ again.
+ So we copy all b->text->redisplay flags up to their windows here,
+ such that mark_window_display_accurate can safely reset
+ b->text->redisplay. */
+ Lisp_Object ws = window_list ();
+ for (; CONSP (ws); ws = XCDR (ws))
+ {
+ struct window *thisw = XWINDOW (XCAR (ws));
+ struct buffer *thisb = XBUFFER (thisw->contents);
+ if (thisb->text->redisplay)
+ thisw->redisplay = true;
+ }
+}
+
#define STOP_POLLING \
do { if (! polling_stopped_here) stop_polling (); \
polling_stopped_here = 1; } while (0)
/* Since frames on a single ASCII terminal share the same
display area, displaying a different frame means redisplay
the whole thing. */
- windows_or_buffers_changed = 48;
SET_FRAME_GARBAGED (sf);
#ifndef DOS_NT
set_tty_color_mode (FRAME_TTY (sf), sf);
if (NILP (Vmemory_full))
prepare_menu_bars ();
- if (windows_or_buffers_changed & !update_mode_lines)
- update_mode_lines = 32;
-
reconsider_clip_changes (w);
/* In most cases selected window displays current buffer. */
{
/* Detect case that we need to write or remove a star in the mode line. */
if ((SAVE_MODIFF < MODIFF) != w->last_had_star)
- {
w->update_mode_line = 1;
- if (buffer_shared_and_changed ())
- update_mode_lines = 33;
- }
if (mode_line_update_needed (w))
w->update_mode_line = 1;
}
- consider_all_windows_p = (update_mode_lines
- || buffer_shared_and_changed ());
-
- /* If specs for an arrow have changed, do thorough redisplay
- to ensure we remove any arrow that should no longer exist. */
- if (overlay_arrows_changed_p ())
- {
- consider_all_windows_p = true;
- windows_or_buffers_changed = 49;
- }
-
/* Normally the message* functions will have already displayed and
updated the echo area, but the frame may have been trashed, or
the update may have been preempted, so display the echo area
if (window_height_changed_p)
{
- consider_all_windows_p = true;
- update_mode_lines = 34;
windows_or_buffers_changed = 50;
/* If window configuration was changed, frames may have been
/* 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. */
- consider_all_windows_p = true;
- windows_or_buffers_changed = 51;
- update_mode_lines = 35;
/* If window configuration was changed, frames may have been
marked garbaged. Clear them or we will experience
clear_garbaged_frames ();
}
- if (VECTORP (Vredisplay__all_windows_cause)
- && windows_or_buffers_changed >= 0
- && windows_or_buffers_changed < ASIZE (Vredisplay__all_windows_cause)
- && INTEGERP (AREF (Vredisplay__all_windows_cause,
- windows_or_buffers_changed)))
- ASET (Vredisplay__all_windows_cause, windows_or_buffers_changed,
- make_number (1 + XINT (AREF (Vredisplay__all_windows_cause,
- windows_or_buffers_changed))));
-
- if (VECTORP (Vredisplay__mode_lines_cause)
- && update_mode_lines >= 0
- && update_mode_lines < ASIZE (Vredisplay__mode_lines_cause)
- && INTEGERP (AREF (Vredisplay__mode_lines_cause,
- update_mode_lines)))
- ASET (Vredisplay__mode_lines_cause, update_mode_lines,
- make_number (1 + XINT (AREF (Vredisplay__mode_lines_cause,
- update_mode_lines))));
+ if (windows_or_buffers_changed && !update_mode_lines)
+ /* Code that sets windows_or_buffers_changed doesn't distinguish whether
+ only the windows's contents needs to be refreshed, or whether the
+ mode-lines also need a refresh. */
+ update_mode_lines = (windows_or_buffers_changed == REDISPLAY_SOME
+ ? REDISPLAY_SOME : 32);
+
+ /* If specs for an arrow have changed, do thorough redisplay
+ to ensure we remove any arrow that should no longer exist. */
+ if (overlay_arrows_changed_p ())
+ /* Apparently, this is the only case where we update other windows,
+ without updating other mode-lines. */
+ windows_or_buffers_changed = 49;
+
+ consider_all_windows_p = (update_mode_lines
+ || windows_or_buffers_changed);
+
+#define AINC(a,i) \
+ if (VECTORP (a) && i >= 0 && i < ASIZE (a) && INTEGERP (AREF (a, i))) \
+ ASET (a, i, make_number (1 + XINT (AREF (a, i))))
+
+ AINC (Vredisplay__all_windows_cause, windows_or_buffers_changed);
+ AINC (Vredisplay__mode_lines_cause, update_mode_lines);
/* Optimize the case that only the line containing the cursor in the
selected window has changed. Variables starting with this_ are
PT == w->last_point
/* Make sure the cursor was last displayed
in this window. Otherwise we have to reposition it. */
+
+ /* PXW: Must be converted to pixels, probably. */
&& 0 <= w->cursor.vpos
&& w->cursor.vpos < WINDOW_TOTAL_LINES (w))
{
cancel:
/* Text changed drastically or point moved off of line. */
- SET_MATRIX_ROW_ENABLED_P (w->desired_matrix, this_line_vpos, 0);
+ SET_MATRIX_ROW_ENABLED_P (w->desired_matrix, this_line_vpos, false);
}
CHARPOS (this_line_start_pos) = 0;
FOR_EACH_FRAME (tail, frame)
XFRAME (frame)->updated_p = 0;
+ propagate_buffer_redisplay ();
+
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
if (FRAME_WINDOW_P (f) || FRAME_TERMCAP_P (f) || f == sf)
{
+ bool gcscrollbars
+ /* Only GC scrollbars when we redisplay the whole frame. */
+ = f->redisplay || !REDISPLAY_SOME_P ();
/* 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 (gcscrollbars && FRAME_TERMINAL (f)->condemn_scroll_bars_hook)
FRAME_TERMINAL (f)->condemn_scroll_bars_hook (f);
if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
redisplay_windows (FRAME_ROOT_WINDOW (f));
+ /* Remember that the invisible frames need to be redisplayed next
+ time they're visible. */
+ else if (!REDISPLAY_SOME_P ())
+ f->redisplay = true;
/* The X error handler may have deleted that frame. */
if (!FRAME_LIVE_P (f))
/* Any scroll bars which redisplay_windows should have
nuked should now go away. */
- if (FRAME_TERMINAL (f)->judge_scroll_bars_hook)
+ if (gcscrollbars && FRAME_TERMINAL (f)->judge_scroll_bars_hook)
FRAME_TERMINAL (f)->judge_scroll_bars_hook (f);
if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
/* Prevent various kinds of signals during display
update. stdio is not robust about handling
- signals, which can cause an apparent I/O
- error. */
+ signals, which can cause an apparent I/O error. */
if (interrupt_input)
unrequest_sigio ();
STOP_POLLING;
- /* Mark windows on frame F to update. If we decide to
- update all frames but windows_or_buffers_changed is
- zero, we assume that only the windows that shows
- current buffer should be really updated. */
- set_window_update_flags
- (XWINDOW (f->root_window),
- (windows_or_buffers_changed ? NULL : current_buffer), 1);
pending |= update_frame (f, 0, 0);
f->cursor_type_changed = 0;
f->updated_p = 1;
struct frame *f = XFRAME (frame);
if (f->updated_p)
{
+ f->redisplay = false;
mark_window_display_accurate (f->root_window, 1);
if (FRAME_TERMINAL (f)->frame_up_to_date_hook)
FRAME_TERMINAL (f)->frame_up_to_date_hook (f);
if (hscroll_windows (selected_window))
goto retry;
- XWINDOW (selected_window)->must_be_updated_p = 1;
+ XWINDOW (selected_window)->must_be_updated_p = true;
pending = update_frame (sf, 0, 0);
sf->cursor_type_changed = 0;
}
if (mini_frame != sf && FRAME_WINDOW_P (mini_frame))
{
- XWINDOW (mini_window)->must_be_updated_p = 1;
+ XWINDOW (mini_window)->must_be_updated_p = true;
pending |= update_frame (mini_frame, 0, 0);
mini_frame->cursor_type_changed = 0;
if (!pending && hscroll_windows (mini_window))
{
/* This has already been done above if
consider_all_windows_p is set. */
+ if (XBUFFER (w->contents)->text->redisplay
+ && buffer_window_count (XBUFFER (w->contents)) > 1)
+ /* This can happen if b->text->redisplay was set during
+ jit-lock. */
+ propagate_buffer_redisplay ();
mark_window_display_accurate_1 (w, 1);
/* Say overlay arrows are up to date. */
FOR_EACH_FRAME (tail, frame)
{
- int this_is_visible = 0;
-
if (XFRAME (frame)->visible)
- this_is_visible = 1;
-
- if (this_is_visible)
new_count++;
}
#endif /* HAVE_WINDOW_SYSTEM */
end_of_redisplay:
+ if (interrupt_input && interrupts_deferred)
+ request_sigio ();
+
unbind_to (count, Qnil);
RESUME_POLLING;
}
if (accurate_p)
{
- b->clip_changed = 0;
- b->prevent_redisplay_optimizations_p = 0;
+ b->clip_changed = false;
+ b->prevent_redisplay_optimizations_p = false;
+ eassert (buffer_window_count (b) > 0);
+ /* Resetting b->text->redisplay is problematic!
+ In order to make it safer to do it here, redisplay_internal must
+ have copied all b->text->redisplay to their respective windows. */
+ b->text->redisplay = false;
BUF_UNCHANGED_MODIFIED (b) = BUF_MODIFF (b);
BUF_OVERLAY_UNCHANGED_MODIFIED (b) = BUF_OVERLAY_MODIFF (b);
else
w->last_point = marker_position (w->pointm);
- w->window_end_valid = 1;
- w->update_mode_line = 0;
+ w->window_end_valid = true;
+ w->update_mode_line = false;
}
+
+ w->redisplay = !accurate_p;
}
redisplay_window_0 (Lisp_Object window)
{
if (displayed_buffer->display_error_modiff < BUF_MODIFF (displayed_buffer))
- redisplay_window (window, 0);
+ redisplay_window (window, false);
return Qnil;
}
redisplay_window_1 (Lisp_Object window)
{
if (displayed_buffer->display_error_modiff < BUF_MODIFF (displayed_buffer))
- redisplay_window (window, 1);
+ redisplay_window (window, true);
return Qnil;
}
\f
occlude point. Only set w->cursor if we found a better
approximation to the cursor position than we have from previously
examined candidate rows belonging to the same continued line. */
- if (/* we already have a candidate row */
+ if (/* We already have a candidate row. */
w->cursor.vpos >= 0
- /* that candidate is not the row we are processing */
+ /* That candidate is not the row we are processing. */
&& MATRIX_ROW (matrix, w->cursor.vpos) != row
/* Make sure cursor.vpos specifies a row whose start and end
charpos occlude point, and it is valid candidate for being a
&& pt_old <= MATRIX_ROW_END_CHARPOS (MATRIX_ROW (matrix, w->cursor.vpos))
&& cursor_row_p (MATRIX_ROW (matrix, w->cursor.vpos)))
{
- struct glyph *g1 =
- MATRIX_ROW_GLYPH_START (matrix, w->cursor.vpos) + w->cursor.hpos;
+ struct glyph *g1
+ = MATRIX_ROW_GLYPH_START (matrix, w->cursor.vpos) + w->cursor.hpos;
/* Don't consider glyphs that are outside TEXT_AREA. */
if (!(row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end))
return 0;
/* Keep the candidate whose buffer position is the closest to
point or has the `cursor' property. */
- if (/* previous candidate is a glyph in TEXT_AREA of that row */
+ if (/* Previous candidate is a glyph in TEXT_AREA of that row. */
w->cursor.hpos >= 0
&& w->cursor.hpos < MATRIX_ROW_USED (matrix, w->cursor.vpos)
&& ((BUFFERP (g1->object)
- && (g1->charpos == pt_old /* an exact match always wins */
+ && (g1->charpos == pt_old /* An exact match always wins. */
|| (BUFFERP (glyph->object)
&& eabs (g1->charpos - pt_old)
< eabs (glyph->charpos - pt_old))))
- /* previous candidate is a glyph from a string that has
- a non-nil `cursor' property */
+ /* Previous candidate is a glyph from a string that has
+ a non-nil `cursor' property. */
|| (STRINGP (g1->object)
&& (!NILP (Fget_char_property (make_number (g1->charpos),
Qcursor, g1->object))
- /* previous candidate is from the same display
+ /* Previous candidate is from the same display
string as this one, and the display string
- came from a text property */
+ came from a text property. */
|| (EQ (g1->object, glyph->object)
&& string_from_text_prop)
/* this candidate is from newline and its
if (! cursor_row_fully_visible_p (w, extra_scroll_margin_lines <= 1, 0)
/* It's possible that the cursor is on the first line of the
buffer, which is partially obscured due to a vscroll
- (Bug#7537). In that case, avoid looping forever . */
+ (Bug#7537). In that case, avoid looping forever. */
&& extra_scroll_margin_lines < w->desired_matrix->nrows - 1)
{
clear_glyph_matrix (w->desired_matrix);
/* If the line start is "too far" away from the window start,
say it takes too much time to compute a new window start. */
if (CHARPOS (start_pos) - IT_CHARPOS (it)
+ /* PXW: Do we need upper bounds here? */
< WINDOW_TOTAL_LINES (w) * WINDOW_TOTAL_COLS (w))
{
int min_distance, distance;
changed on window's frame. In that case, redisplay_internal will retry. */
static void
-redisplay_window (Lisp_Object window, int just_this_one_p)
+redisplay_window (Lisp_Object window, bool just_this_one_p)
{
struct window *w = XWINDOW (window);
struct frame *f = XFRAME (w->frame);
int tem;
struct it it;
/* Record it now because it's overwritten. */
- int current_matrix_up_to_date_p = 0;
- int used_current_matrix_p = 0;
+ bool current_matrix_up_to_date_p = false;
+ bool used_current_matrix_p = false;
/* This is less strict than current_matrix_up_to_date_p.
It indicates that the buffer contents and narrowing are unchanged. */
- int buffer_unchanged_p = 0;
+ bool buffer_unchanged_p = false;
int temp_scroll_step = 0;
ptrdiff_t count = SPECPDL_INDEX ();
int rc;
*w->desired_matrix->method = 0;
#endif
+ if (!just_this_one_p
+ && REDISPLAY_SOME_P ()
+ && !w->redisplay
+ && !f->redisplay
+ && !buffer->text->redisplay
+ && BUF_PT (buffer) == w->last_point)
+ return;
+
/* Make sure that both W's markers are valid. */
eassert (XMARKER (w->start)->buffer == buffer);
eassert (XMARKER (w->pointm)->buffer == buffer);
|| buffer->clip_changed
|| buffer->prevent_redisplay_optimizations_p);
+ if (!just_this_one_p)
+ /* If `just_this_one_p' is set, we apparently set must_be_updated_p more
+ cleverly elsewhere. */
+ w->must_be_updated_p = true;
+
if (MINI_WINDOW_P (w))
{
if (w == XWINDOW (echo_area_window)
if (XMARKER (w->start)->buffer == current_buffer)
compute_window_start_on_continuation_line (w);
- w->window_end_valid = 0;
+ w->window_end_valid = false;
/* If so, we also can't rely on current matrix
and should not fool try_cursor_movement below. */
- current_matrix_up_to_date_p = 0;
+ current_matrix_up_to_date_p = false;
}
/* Some sanity checks. */
this may be a bit late to catch such changes, but the rest of
redisplay goes (non-fatally) haywire when the display table is
changed, so why should we worry about doing any better? */
- if (current_buffer->width_run_cache)
+ if (current_buffer->width_run_cache
+ || (current_buffer->base_buffer
+ && current_buffer->base_buffer->width_run_cache))
{
struct Lisp_Char_Table *disptab = buffer_display_table ();
if (! disptab_matches_widthtab
(disptab, XVECTOR (BVAR (current_buffer, width_table))))
{
- invalidate_region_cache (current_buffer,
- current_buffer->width_run_cache,
- BEG, Z);
+ struct buffer *buf = current_buffer;
+
+ if (buf->base_buffer)
+ buf = buf->base_buffer;
+ invalidate_region_cache (buf, buf->width_run_cache, BEG, Z);
recompute_width_table (current_buffer, disptab);
}
}
SET_TEXT_POS_FROM_MARKER (startp, w->start);
w->start_at_line_beg = (CHARPOS (startp) == BEGV
- || FETCH_BYTE (BYTEPOS (startp) - 1) == '\n');
+ || FETCH_BYTE (BYTEPOS (startp) - 1) == '\n');
/* Display the mode line, if we must. */
if ((update_mode_line
&& (WINDOW_WANTS_MODELINE_P (w)
|| WINDOW_WANTS_HEADER_LINE_P (w)))
{
+
display_mode_lines (w);
/* If mode line height has changed, arrange for a thorough
redisplay_tool_bar (f);
#else
if (WINDOWP (f->tool_bar_window)
- && (FRAME_TOOL_BAR_LINES (f) > 0
+ && (FRAME_TOOL_BAR_HEIGHT (f) > 0
|| !NILP (Vauto_resize_tool_bars))
&& redisplay_tool_bar (f))
ignore_mouse_drag_p = 1;
update_begin (f);
block_input ();
if (draw_window_fringes (w, 1))
- x_draw_vertical_border (w);
+ {
+ if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
+ x_draw_right_divider (w);
+ else
+ x_draw_vertical_border (w);
+ }
unblock_input ();
update_end (f);
}
+
+ if (WINDOW_BOTTOM_DIVIDER_WIDTH (w))
+ x_draw_bottom_divider (w);
#endif /* HAVE_WINDOW_SYSTEM */
/* We go to this label, with fonts_changed set, if it is
set_buffer_internal_1 (old);
/* Avoid an abort in TEMP_SET_PT_BOTH if the buffer has become
- shorter. This can be caused by log truncation in *Messages*. */
+ shorter. This can be caused by log truncation in *Messages*. */
if (CHARPOS (lpoint) <= ZV)
TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
/* Disable lines that must be updated. */
for (i = 0; i < nrows_scrolled; ++i)
- (start_row + i)->enabled_p = 0;
+ (start_row + i)->enabled_p = false;
/* Re-compute Y positions. */
min_y = WINDOW_HEADER_LINE_HEIGHT (w);
/* Disable rows not reused. */
for (row -= nrows_scrolled; row < bottom_row; ++row)
- row->enabled_p = 0;
+ row->enabled_p = false;
/* Point may have moved to a different line, so we cannot assume that
the previous cursor position is valid; locate the correct row. */
/* Disable frame rows whose corresponding window rows have
been disabled in try_window_id. */
if (!window_row->enabled_p)
- frame_row->enabled_p = 0;
+ frame_row->enabled_p = false;
++window_row, ++frame_row;
}
Value is
- 1 if display has been updated
- 0 if otherwise unsuccessful
+ >= 1 if successful, i.e. display has been updated
+ specifically:
+ 1 means the changes were in front of a newline that precedes
+ the window start, and the whole current matrix was reused
+ 2 means the changes were after the last position displayed
+ in the window, and the whole current matrix was reused
+ 3 means portions of the current matrix were reused, while
+ some of the screen lines were redrawn
-1 if redisplay with same window start is known not to succeed
+ 0 if otherwise unsuccessful
The following steps are performed:
if (windows_or_buffers_changed || f->cursor_type_changed)
GIVE_UP (2);
+ /* This function's optimizations cannot be used if overlays have
+ changed in the buffer displayed by the window, so give up if they
+ have. */
+ if (w->last_overlay_modified != OVERLAY_MODIFF)
+ GIVE_UP (21);
+
/* Verify that narrowing has not changed.
Also verify that we were not told to prevent redisplay optimizations.
It would be nice to further
= run.current_y = run.desired_y = run.height = 0;
first_unchanged_at_end_row = NULL;
}
- IF_DEBUG (debug_dvpos = dvpos; debug_dy = dy);
+ IF_DEBUG ((debug_dvpos = dvpos, debug_dy = dy));
/* Find the cursor if not already found. We have to decide whether
the current matrix? I don't think so, so we mark rows
displayed invalid in the current matrix by setting their
enabled_p flag to zero. */
- MATRIX_ROW (w->current_matrix, it.vpos)->enabled_p = 0;
+ SET_MATRIX_ROW_ENABLED_P (w->current_matrix, it.vpos, false);
if (display_line (&it))
last_text_row_at_end = it.glyph_row - 1;
}
else
emacs_abort ();
- IF_DEBUG (debug_end_pos = w->window_end_pos;
- debug_end_vpos = w->window_end_vpos);
+ IF_DEBUG ((debug_end_pos = w->window_end_pos,
+ debug_end_vpos = w->window_end_vpos));
/* Record that display has not been completed. */
w->window_end_valid = 0;
1-``pixel'' wide, so they hit the equality too early. This grace
is needed only for R2L rows that are not continued, to produce
one extra blank where we could display the cursor. */
- if (it->current_x >= it->last_visible_x
- + (!FRAME_WINDOW_P (f)
- && it->glyph_row->reversed_p
- && !it->glyph_row->continued_p))
+ if ((it->current_x >= it->last_visible_x
+ + (!FRAME_WINDOW_P (f)
+ && it->glyph_row->reversed_p
+ && !it->glyph_row->continued_p))
+ /* If the window has display margins, we will need to extend
+ their face even if the text area is filled. */
+ && !(WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+ || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0))
return;
/* The default face, possibly remapped. */
it->glyph_row->glyphs[TEXT_AREA][0].face_id = face->id;
it->glyph_row->used[TEXT_AREA] = 1;
}
+ /* Mode line and the header line don't have margins, and
+ likewise the frame's tool-bar window, if there is any. */
+ if (!(it->glyph_row->mode_line_p
+#if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS)
+ || (WINDOWP (f->tool_bar_window)
+ && it->w == XWINDOW (f->tool_bar_window))
+#endif
+ ))
+ {
+ if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+ && it->glyph_row->used[LEFT_MARGIN_AREA] == 0)
+ {
+ it->glyph_row->glyphs[LEFT_MARGIN_AREA][0] = space_glyph;
+ it->glyph_row->glyphs[LEFT_MARGIN_AREA][0].face_id =
+ default_face->id;
+ it->glyph_row->used[LEFT_MARGIN_AREA] = 1;
+ }
+ if (WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0
+ && it->glyph_row->used[RIGHT_MARGIN_AREA] == 0)
+ {
+ it->glyph_row->glyphs[RIGHT_MARGIN_AREA][0] = space_glyph;
+ it->glyph_row->glyphs[RIGHT_MARGIN_AREA][0].face_id =
+ default_face->id;
+ it->glyph_row->used[RIGHT_MARGIN_AREA] = 1;
+ }
+ }
#ifdef HAVE_WINDOW_SYSTEM
if (it->glyph_row->reversed_p)
{
it->object = make_number (0);
it->c = it->char_to_display = ' ';
it->len = 1;
+
+ if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+ && (it->glyph_row->used[LEFT_MARGIN_AREA]
+ < WINDOW_LEFT_MARGIN_WIDTH (it->w))
+ && !it->glyph_row->mode_line_p
+ && default_face->background != FRAME_BACKGROUND_PIXEL (f))
+ {
+ struct glyph *g = it->glyph_row->glyphs[LEFT_MARGIN_AREA];
+ struct glyph *e = g + it->glyph_row->used[LEFT_MARGIN_AREA];
+
+ for (it->current_x = 0; g < e; g++)
+ it->current_x += g->pixel_width;
+
+ it->area = LEFT_MARGIN_AREA;
+ it->face_id = default_face->id;
+ while (it->glyph_row->used[LEFT_MARGIN_AREA]
+ < WINDOW_LEFT_MARGIN_WIDTH (it->w))
+ {
+ PRODUCE_GLYPHS (it);
+ /* term.c:produce_glyphs advances it->current_x only for
+ TEXT_AREA. */
+ it->current_x += it->pixel_width;
+ }
+
+ it->current_x = saved_x;
+ it->area = TEXT_AREA;
+ }
+
/* The last row's blank glyphs 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;
-
PRODUCE_GLYPHS (it);
while (it->current_x <= it->last_visible_x)
PRODUCE_GLYPHS (it);
+ if (WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0
+ && (it->glyph_row->used[RIGHT_MARGIN_AREA]
+ < WINDOW_RIGHT_MARGIN_WIDTH (it->w))
+ && !it->glyph_row->mode_line_p
+ && default_face->background != FRAME_BACKGROUND_PIXEL (f))
+ {
+ struct glyph *g = it->glyph_row->glyphs[RIGHT_MARGIN_AREA];
+ struct glyph *e = g + it->glyph_row->used[RIGHT_MARGIN_AREA];
+
+ for ( ; g < e; g++)
+ it->current_x += g->pixel_width;
+
+ it->area = RIGHT_MARGIN_AREA;
+ it->face_id = default_face->id;
+ while (it->glyph_row->used[RIGHT_MARGIN_AREA]
+ < WINDOW_RIGHT_MARGIN_WIDTH (it->w))
+ {
+ PRODUCE_GLYPHS (it);
+ it->current_x += it->pixel_width;
+ }
+
+ it->area = TEXT_AREA;
+ }
+
/* Don't count these blanks really. It would let us insert a left
truncation glyph below and make us set the cursor on them, maybe. */
it->current_x = saved_x;
}
else if (it->bidi_p)
RECORD_MAX_MIN_POS (it);
+ if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+ || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)
+ extend_face_to_end_of_line (it);
}
else if (CHAR_GLYPH_PADDING_P (*glyph)
&& !FRAME_WINDOW_P (it->f))
it->max_descent = descent;
it->max_phys_ascent = phys_ascent;
it->max_phys_descent = phys_descent;
+ if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+ || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)
+ extend_face_to_end_of_line (it);
}
else if (wrap_row_used > 0)
{
row->continued_p = 1;
glyph->pixel_width = it->last_visible_x - x;
it->starts_in_middle_of_char_p = 1;
+ if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+ || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)
+ extend_face_to_end_of_line (it);
}
else
{
itb.string.s = NULL;
itb.string.lstring = Qnil;
itb.string.bufpos = 0;
+ itb.string.from_disp_str = 0;
itb.string.unibyte = 0;
/* We have no window to use here for ignoring window-specific
overlays. Using NULL for window pointer will cause
of this or previous line to make sure we are before point in
the logical order (since the move_it_* functions can only
move forward). */
+ reseat:
reseat_at_previous_visible_line_start (&it);
it.current_x = it.hpos = it.current_y = it.vpos = 0;
if (IT_CHARPOS (it) != PT)
- move_it_to (&it, overshoot_expected ? PT - 1 : PT,
- -1, -1, -1, MOVE_TO_POS);
+ {
+ move_it_to (&it, overshoot_expected ? PT - 1 : PT,
+ -1, -1, -1, MOVE_TO_POS);
+ /* If we missed point because the character there is
+ displayed out of a display vector that has more than one
+ glyph, retry expecting overshoot. */
+ if (it.method == GET_FROM_DISPLAY_VECTOR
+ && it.current.dpvec_index > 0
+ && !overshoot_expected)
+ {
+ overshoot_expected = true;
+ goto reseat;
+ }
+ else if (IT_CHARPOS (it) != PT && !overshoot_expected)
+ move_it_in_display_line (&it, PT, -1, MOVE_TO_POS);
+ }
pt_x = it.current_x;
pt_vpos = it.vpos;
if (dir > 0 || overshoot_expected)
else if (pixel_width <= 0)
pixel_width = 1;
- /* If there's a display string at point, we are actually at the
- glyph to the left of point, so we need to correct the X
- coordinate. */
+ /* If there's a display string (or something similar) at point,
+ we are actually at the glyph to the left of point, so we need
+ to correct the X coordinate. */
if (overshoot_expected)
- pt_x += pixel_width;
+ {
+ if (it.bidi_p)
+ pt_x += pixel_width * it.bidi_it.scan_dir;
+ else
+ pt_x += pixel_width;
+ }
/* Compute target X coordinate, either to the left or to the
right of point. On TTY frames, all characters have the same
character at point. */
if (FRAME_WINDOW_P (it.f) && dir < 0)
{
- struct text_pos new_pos = it.current.pos;
+ struct text_pos new_pos;
enum move_it_result rc = MOVE_X_REACHED;
+ if (it.current_x == 0)
+ get_next_display_element (&it);
+ if (it.what == IT_COMPOSITION)
+ {
+ new_pos.charpos = it.cmp_it.charpos;
+ new_pos.bytepos = -1;
+ }
+ else
+ new_pos = it.current.pos;
+
while (it.current_x + it.pixel_width <= target_x
&& rc == MOVE_X_REACHED)
{
int new_x = it.current_x + it.pixel_width;
- new_pos = it.current.pos;
+ /* For composed characters, we want the position of the
+ first character in the grapheme cluster (usually, the
+ composition's base character), whereas it.current
+ might give us the position of the _last_ one, e.g. if
+ the composition is rendered in reverse due to bidi
+ reordering. */
+ if (it.what == IT_COMPOSITION)
+ {
+ new_pos.charpos = it.cmp_it.charpos;
+ new_pos.bytepos = -1;
+ }
+ else
+ new_pos = it.current.pos;
if (new_x == it.current_x)
new_x++;
rc = move_it_in_display_line_to (&it, ZV, new_x,
if (ITERATOR_AT_END_OF_LINE_P (&it) && !target_is_eol_p)
break;
}
- /* If we ended up on a composed character inside
- bidi-reordered text (e.g., Hebrew text with diacritics),
- the iterator gives us the buffer position of the last (in
- logical order) character of the composed grapheme cluster,
- which is not what we want. So we cheat: we compute the
- character position of the character that follows (in the
- logical order) the one where the above loop stopped. That
- character will appear on display to the left of point. */
- if (it.bidi_p
- && it.bidi_it.scan_dir == -1
- && new_pos.charpos - IT_CHARPOS (it) > 1)
- {
- new_pos.charpos = IT_CHARPOS (it) + 1;
- new_pos.bytepos = CHAR_TO_BYTE (new_pos.charpos);
- }
+ /* The previous position we saw in the loop is the one we
+ want. */
+ if (new_pos.bytepos == -1)
+ new_pos.bytepos = CHAR_TO_BYTE (new_pos.charpos);
it.current.pos = new_pos;
}
else
eassert (!FRAME_WINDOW_P (f));
init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID);
it.first_visible_x = 0;
- it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+ it.last_visible_x = FRAME_PIXEL_WIDTH (f);
#elif defined (HAVE_X_WINDOWS) /* X without toolkit. */
if (FRAME_WINDOW_P (f))
{
init_iterator (&it, menu_w, -1, -1, menu_w->desired_matrix->rows,
MENU_FACE_ID);
it.first_visible_x = 0;
- it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+ it.last_visible_x = FRAME_PIXEL_WIDTH (f);
}
else
#endif /* not USE_X_TOOLKIT and not USE_GTK */
{
struct glyph_row *row = it.glyph_row + i;
clear_glyph_row (row);
- row->enabled_p = 1;
+ row->enabled_p = true;
row->full_width_p = 1;
}
compute_line_metrics (&it);
}
-#ifdef HAVE_MENUS
/* Deep copy of a glyph row, including the glyphs. */
static void
deep_copy_glyph_row (struct glyph_row *to, struct glyph_row *from)
row->full_width_p = 1;
saved_reversed = row->reversed_p;
row->reversed_p = 0;
- row->enabled_p = 1;
+ row->enabled_p = true;
/* Arrange for the menu item glyphs to start at (X,Y) and have the
desired face. */
row->full_width_p = saved_width;
row->reversed_p = saved_reversed;
}
-#endif /* HAVE_MENUS */
\f
/***********************************************************************
Mode Line
the number of windows whose mode lines were redisplayed. */
static int
-redisplay_mode_lines (Lisp_Object window, int force)
+redisplay_mode_lines (Lisp_Object window, bool force)
{
int nwindows = 0;
/* Display mode lines. */
clear_glyph_matrix (w->desired_matrix);
if (display_mode_lines (w))
- {
- ++nwindows;
- w->must_be_updated_p = 1;
- }
+ ++nwindows;
/* Restore old settings. */
set_buffer_internal_1 (old);
XFRAME (new_frame)->selected_window = old_frame_selected_window;
selected_frame = old_selected_frame;
selected_window = old_selected_window;
+ if (n > 0)
+ w->must_be_updated_p = true;
return n;
}
init_iterator (&it, w, -1, -1, NULL, face_id);
/* Don't extend on a previously drawn mode-line.
This may happen if called from pos_visible_p. */
- it.glyph_row->enabled_p = 0;
+ it.glyph_row->enabled_p = false;
prepare_desired_row (it.glyph_row);
it.glyph_row->mode_line_p = 1;
the drawing area, set S->extends_to_end_of_line_p. */
if (start == s->row->used[s->area]
- && s->area == TEXT_AREA
&& ((s->row->fill_line_p
&& (s->hl == DRAW_NORMAL_TEXT
|| s->hl == DRAW_IMAGE_RAISED
/* X is relative to the left edge of W, without scroll bars
or fringes. */
area_left = WINDOW_LEFT_EDGE_X (w);
- last_x = WINDOW_LEFT_EDGE_X (w) + WINDOW_TOTAL_WIDTH (w);
+ last_x = (WINDOW_LEFT_EDGE_X (w) + WINDOW_PIXEL_WIDTH (w)
+ - (row->mode_line_p ? WINDOW_RIGHT_DIVIDER_WIDTH (w) : 0));
}
else
{
f = XFRAME (w->frame);
if (updated_row->full_width_p)
- max_x = WINDOW_TOTAL_WIDTH (w);
+ max_x = (WINDOW_PIXEL_WIDTH (w)
+ - (updated_row->mode_line_p ? WINDOW_RIGHT_DIVIDER_WIDTH (w) : 0));
else
max_x = window_box_width (w, updated_area);
max_y = window_text_bottom_y (w);
/* Erase the image of a cursor of window W from the screen. */
-#ifndef WINDOWSNT
+#ifndef HAVE_NTGUI
static
#endif
void
cleared = 1;
}
- reset_mouse_highlight (hlinfo);
+ hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
+ hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
+ hlinfo->mouse_face_window = Qnil;
+ hlinfo->mouse_face_overlay = Qnil;
return cleared;
}
-/* Return non-zero if the coordinates HPOS and VPOS on windows W are
+/* Return true if the coordinates HPOS and VPOS on windows W are
within the mouse face on that window. */
-static int
+static bool
coords_in_mouse_face_p (struct window *w, int hpos, int vpos)
{
Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
/* Quickly resolve the easy cases. */
if (!(WINDOWP (hlinfo->mouse_face_window)
&& XWINDOW (hlinfo->mouse_face_window) == w))
- return 0;
+ return false;
if (vpos < hlinfo->mouse_face_beg_row
|| vpos > hlinfo->mouse_face_end_row)
- return 0;
+ return false;
if (vpos > hlinfo->mouse_face_beg_row
&& vpos < hlinfo->mouse_face_end_row)
- return 1;
+ return true;
if (!MATRIX_ROW (w->current_matrix, vpos)->reversed_p)
{
if (hlinfo->mouse_face_beg_row == hlinfo->mouse_face_end_row)
{
if (hlinfo->mouse_face_beg_col <= hpos && hpos < hlinfo->mouse_face_end_col)
- return 1;
+ return true;
}
else if ((vpos == hlinfo->mouse_face_beg_row
&& hpos >= hlinfo->mouse_face_beg_col)
|| (vpos == hlinfo->mouse_face_end_row
&& hpos < hlinfo->mouse_face_end_col))
- return 1;
+ return true;
}
else
{
if (hlinfo->mouse_face_beg_row == hlinfo->mouse_face_end_row)
{
if (hlinfo->mouse_face_end_col < hpos && hpos <= hlinfo->mouse_face_beg_col)
- return 1;
+ return true;
}
else if ((vpos == hlinfo->mouse_face_beg_row
&& hpos <= hlinfo->mouse_face_beg_col)
|| (vpos == hlinfo->mouse_face_end_row
&& hpos > hlinfo->mouse_face_end_col))
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/* EXPORT:
- Non-zero if physical cursor of window W is within mouse face. */
+ True if physical cursor of window W is within mouse face. */
-int
+bool
cursor_in_mouse_face_p (struct window *w)
{
int hpos = w->phys_cursor.hpos;
cursor = FRAME_X_OUTPUT (f)->text_cursor;
else if (EQ (pointer, intern ("hdrag")))
cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
+ else if (EQ (pointer, intern ("nhdrag")))
+ cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor;
#ifdef HAVE_X_WINDOWS
else if (EQ (pointer, intern ("vdrag")))
cursor = FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
help_echo_string = build_string ("drag-mouse-1: resize");
}
+ else if (part == ON_RIGHT_DIVIDER)
+ {
+ cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
+ help_echo_string = build_string ("drag-mouse-1: resize");
+ }
+ else if (part == ON_BOTTOM_DIVIDER)
+ {
+ cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor;
+ help_echo_string = build_string ("drag-mouse-1: resize");
+ }
else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE
|| part == ON_SCROLL_BAR)
cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
do it for frames with vertical scroll bars because either the
right scroll bar of a window, or the left scroll bar of its
neighbor will suffice as a border. */
- if (FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (w->frame)))
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS (f) || FRAME_RIGHT_DIVIDER_WIDTH (f))
return;
/* Note: It is necessary to redraw both the left and the right
FRAME_RIF (f)->draw_vertical_window_border (w, x1, y0, y1);
}
+
if (!WINDOW_LEFTMOST_P (w)
&& !WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
{
}
+/* Draw window dividers for window W. */
+
+void
+x_draw_right_divider (struct window *w)
+{
+ struct frame *f = WINDOW_XFRAME (w);
+
+ if (w->mini || w->pseudo_window_p)
+ return;
+ else if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
+ {
+ int x0 = WINDOW_RIGHT_EDGE_X (w) - WINDOW_RIGHT_DIVIDER_WIDTH (w);
+ int x1 = WINDOW_RIGHT_EDGE_X (w);
+ int y0 = WINDOW_TOP_EDGE_Y (w);
+ /* The bottom divider prevails. */
+ int y1 = WINDOW_BOTTOM_EDGE_Y (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w);
+
+ FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1);
+ }
+}
+
+static void
+x_draw_bottom_divider (struct window *w)
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+
+ if (w->mini || w->pseudo_window_p)
+ return;
+ else if (WINDOW_BOTTOM_DIVIDER_WIDTH (w))
+ {
+ int x0 = WINDOW_LEFT_EDGE_X (w);
+ int x1 = WINDOW_RIGHT_EDGE_X (w);
+ int y0 = WINDOW_BOTTOM_EDGE_Y (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w);
+ int y1 = WINDOW_BOTTOM_EDGE_Y (w);
+
+ FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1);
+ }
+}
+
/* Redraw the part of window W intersection rectangle FR. Pixel
coordinates in FR are frame-relative. Call this function with
input blocked. Value is non-zero if the exposure overwrites
/* Frame-relative pixel rectangle of W. */
wr.x = WINDOW_LEFT_EDGE_X (w);
wr.y = WINDOW_TOP_EDGE_Y (w);
- wr.width = WINDOW_TOTAL_WIDTH (w);
- wr.height = WINDOW_TOTAL_HEIGHT (w);
+ wr.width = WINDOW_PIXEL_WIDTH (w);
+ wr.height = WINDOW_PIXEL_HEIGHT (w);
if (x_intersect_rectangles (fr, &wr, &r))
{
fr);
/* Draw border between windows. */
- x_draw_vertical_border (w);
+ if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
+ x_draw_right_divider (w);
+ else
+ x_draw_vertical_border (w);
+
+ if (WINDOW_BOTTOM_DIVIDER_WIDTH (w))
+ x_draw_bottom_divider (w);
/* Turn the cursor on again. */
if (cursor_cleared_p
defsubr (&Strace_to_stderr);
#endif
#ifdef HAVE_WINDOW_SYSTEM
- defsubr (&Stool_bar_lines_needed);
+ defsubr (&Stool_bar_height);
defsubr (&Slookup_image_map);
#endif
defsubr (&Sline_pixel_height);
defsubr (&Sformat_mode_line);
defsubr (&Sinvisible_p);
defsubr (&Scurrent_bidi_paragraph_direction);
+ defsubr (&Swindow_text_pixel_size);
defsubr (&Smove_point_visually);
DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
echo_area_window = minibuf_window;
r->top_line = FRAME_TOP_MARGIN (f);
- r->total_lines = FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f);
+ r->pixel_top = r->top_line * FRAME_LINE_HEIGHT (f);
r->total_cols = FRAME_COLS (f);
+ r->pixel_width = r->total_cols * FRAME_COLUMN_WIDTH (f);
+ r->total_lines = FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f);
+ r->pixel_height = r->total_lines * FRAME_LINE_HEIGHT (f);
m->top_line = FRAME_LINES (f) - 1;
- m->total_lines = 1;
+ m->pixel_top = m->top_line * FRAME_LINE_HEIGHT (f);
m->total_cols = FRAME_COLS (f);
+ m->pixel_width = m->total_cols * FRAME_COLUMN_WIDTH (f);
+ m->total_lines = 1;
+ m->pixel_height = m->total_lines * FRAME_LINE_HEIGHT (f);
scratch_glyph_row.glyphs[TEXT_AREA] = scratch_glyphs;
scratch_glyph_row.glyphs[TEXT_AREA + 1]