static bool message_enable_multibyte;
-/* 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). */
+/* At each redisplay cycle, we should refresh everything there is to refresh.
+ To do that efficiently, we use many optimizations that try to make sure we
+ don't waste too much time updating things that haven't changed.
+ The coarsest such optimization is that, in the most common cases, we only
+ look at the selected-window.
+
+ To know whether other windows should be considered for redisplay, we use the
+ variable windows_or_buffers_changed: as long as it is 0, it means that we
+ have not noticed anything that should require updating anything else than
+ the selected-window. If it is set to REDISPLAY_SOME, it means that since
+ last redisplay, some changes have been made which could impact other
+ windows. To know which ones need redisplay, every buffer, window, and frame
+ has a `redisplay' bit, which (if true) means that this object needs to be
+ redisplayed. If windows_or_buffers_changed is 0, we know there's no point
+ looking for those `redisplay' bits (actually, there might be some such bits
+ set, but then only on objects which aren't displayed anyway).
+
+ OTOH if it's non-zero we wil have to loop through all windows and then check
+ the `redisplay' bit of the corresponding window, frame, and buffer, in order
+ to decide whether that window needs attention or not. Not that we can't
+ just look at the frame's redisplay bit to decide that the whole frame can be
+ skipped, since even if the frame's redisplay bit is unset, some of its
+ windows's redisplay bits may be set.
+
+ Mostly for historical reasons, windows_or_buffers_changed can also take
+ other non-zero values. In that case, the precise value doesn't matter (it
+ encodes the cause of the setting but is only used for debugging purposes),
+ and what it means is that we shouldn't pay attention to any `redisplay' bits
+ and we should simply try and redisplay every window out there. */
-int update_mode_lines;
+int windows_or_buffers_changed;
-/* 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). */
+/* Nonzero if we should redraw the mode lines on the next redisplay.
+ Similarly to `windows_or_buffers_changed', If it has value REDISPLAY_SOME,
+ then only redisplay the mode lines in those buffers/windows/frames where the
+ `redisplay' bit has been set.
+ For any other value, redisplay all mode lines (the number used is then only
+ used to track down the cause for this full-redisplay).
+
+ The `redisplay' bits are the same as those used for
+ windows_or_buffers_changed, and setting windows_or_buffers_changed also
+ causes recomputation of the mode lines of all those windows. IOW this
+ variable only has an effect if windows_or_buffers_changed is zero, in which
+ case we should only need to redisplay the mode-line of those objects with
+ a `redisplay' bit set but not the window's text content (tho we may still
+ need to refresh the text content of the selected-window). */
-int windows_or_buffers_changed;
+int update_mode_lines;
/* True after display_mode_line if %l was used and it displayed a
line number. */
static void iterate_out_of_display_property (struct it *);
static void pop_it (struct it *);
static void redisplay_internal (void);
-static bool echo_area_display (bool);
+static void echo_area_display (bool);
static void redisplay_windows (Lisp_Object);
static void redisplay_window (Lisp_Object, bool);
static Lisp_Object redisplay_window_error (Lisp_Object);
static void notice_overwritten_cursor (struct window *,
enum glyph_row_area,
int, int, int, int);
+static int normal_char_height (struct font *, int);
+static void normal_char_ascent_descent (struct font *, int, int *, int *);
+
static void append_stretch_glyph (struct it *, Lisp_Object,
int, int, int);
+static Lisp_Object get_it_property (struct it *, Lisp_Object);
+static Lisp_Object calc_line_height_property (struct it *, Lisp_Object,
+ struct font *, int, bool);
#endif /* HAVE_WINDOW_SYSTEM */
if (face)
{
if (face->font)
- height = FONT_HEIGHT (face->font);
+ height = normal_char_height (face->font, -1);
if (face->box_line_width > 0)
height += 2 * face->box_line_width;
}
struct glyph *glyph, int *xp, int *yp, int *heightp)
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
- int x, y, wd, h, h0, y0;
+ int x, y, wd, h, h0, y0, ascent;
/* Compute the width of the rectangle to draw. If on a stretch
glyph, and `x-stretch-block-cursor' is nil, don't draw a
wd = min (FRAME_COLUMN_WIDTH (f), wd);
w->phys_cursor_width = wd;
- y = w->phys_cursor.y + row->ascent - glyph->ascent;
+ /* Don't let the hollow cursor glyph descend below the glyph row's
+ ascent value, lest the hollow cursor looks funny. */
+ y = w->phys_cursor.y;
+ ascent = row->ascent;
+ if (row->ascent < glyph->ascent)
+ {
+ y =- glyph->ascent - row->ascent;
+ ascent = glyph->ascent;
+ }
/* If y is below window bottom, ensure that we still see a cursor. */
h0 = min (FRAME_LINE_HEIGHT (f), row->visible_height);
- h = max (h0, glyph->ascent + glyph->descent);
- h0 = min (h0, glyph->ascent + glyph->descent);
+ h = max (h0, ascent + glyph->descent);
+ h0 = min (h0, ascent + glyph->descent);
y0 = WINDOW_HEADER_LINE_HEIGHT (w);
if (y < y0)
free realized faces now because they depend on face definitions
that might have changed. Don't free faces while there might be
desired matrices pending which reference these faces. */
- if (face_change && !inhibit_free_realized_faces)
+ if (!inhibit_free_realized_faces)
{
- face_change = false;
- free_all_realized_faces (Qnil);
+ if (face_change)
+ {
+ face_change = false;
+ free_all_realized_faces (Qnil);
+ }
+ else if (XFRAME (w->frame)->face_change)
+ {
+ XFRAME (w->frame)->face_change = 0;
+ free_all_realized_faces (w->frame);
+ }
}
/* Perhaps remap BASE_FACE_ID to a user-specified alternative. */
else
{
Lisp_Object fns, fn;
- struct gcpro gcpro1, gcpro2;
fns = Qnil;
- GCPRO2 (val, fns);
for (; CONSP (val); val = XCDR (val))
{
else
safe_call1 (fn, pos);
}
-
- UNGCPRO;
}
unbind_to (count, Qnil);
/* With bidi iteration, the character before the current
in the visual order cannot be found by simple
iteration, because "reverse" reordering is not
- supported. Instead, we need to use the move_it_*
- family of functions. */
+ supported. Instead, we need to start from the string
+ beginning and go all the way to the current string
+ position, remembering the previous position. */
/* Ignore face changes before the first visible
character on this display line. */
if (it->current_x <= it->first_visible_x)
return it->face_id;
SAVE_IT (it_copy, *it, it_copy_data);
- /* Implementation note: Since move_it_in_display_line
- works in the iterator geometry, and thinks the first
- character is always the leftmost, even in R2L lines,
- we don't need to distinguish between the R2L and L2R
- cases here. */
- move_it_in_display_line (&it_copy, SCHARS (it_copy.string),
- it_copy.current_x - 1, MOVE_TO_X);
- charpos = IT_STRING_CHARPOS (it_copy);
+ IT_STRING_CHARPOS (it_copy) = 0;
+ bidi_init_it (0, 0, FRAME_WINDOW_P (it_copy.f), &it_copy.bidi_it);
+
+ do
+ {
+ charpos = IT_STRING_CHARPOS (it_copy);
+ if (charpos >= SCHARS (it->string))
+ break;
+ bidi_move_to_visually_next (&it_copy.bidi_it);
+ }
+ while (IT_STRING_CHARPOS (it_copy) != IT_STRING_CHARPOS (*it));
+
RESTORE_IT (it, it, it_copy_data);
}
else
{
if (before_p)
{
+ int current_x;
+
/* With bidi iteration, the character before the current
in the visual order cannot be found by simple
iteration, because "reverse" reordering is not
supported. Instead, we need to use the move_it_*
- family of functions. */
+ family of functions, and move to the previous
+ character starting from the beginning of the visual
+ line. */
/* Ignore face changes before the first visible
character on this display line. */
if (it->current_x <= it->first_visible_x)
character is always the leftmost, even in R2L lines,
we don't need to distinguish between the R2L and L2R
cases here. */
- move_it_in_display_line (&it_copy, ZV,
- it_copy.current_x - 1, MOVE_TO_X);
+ current_x = it_copy.current_x;
+ move_it_vertically_backward (&it_copy, 0);
+ move_it_in_display_line (&it_copy, ZV, current_x - 1, MOVE_TO_X);
pos = it_copy.current.pos;
RESTORE_IT (it, it, it_copy_data);
}
if (STRINGP (it->string))
{
- Lisp_Object end_charpos, limit, charpos;
+ Lisp_Object end_charpos, limit;
/* Get the value of the invisible text property at the
current position. Value will be nil if there is no such
property. */
- charpos = make_number (IT_STRING_CHARPOS (*it));
- prop = Fget_text_property (charpos, Qinvisible, it->string);
+ end_charpos = make_number (IT_STRING_CHARPOS (*it));
+ prop = Fget_text_property (end_charpos, Qinvisible, it->string);
invis = TEXT_PROP_MEANS_INVISIBLE (prop);
if (invis != 0 && IT_STRING_CHARPOS (*it) < it->end_charpos)
XSETINT (limit, len);
do
{
- end_charpos = Fnext_single_property_change (charpos, Qinvisible,
- it->string, limit);
+ end_charpos
+ = Fnext_single_property_change (end_charpos, Qinvisible,
+ it->string, limit);
+ /* Since LIMIT is always an integer, so should be the
+ value returned by Fnext_single_property_change. */
+ eassert (INTEGERP (end_charpos));
if (INTEGERP (end_charpos))
{
endpos = XFASTINT (end_charpos);
if (invis == 2)
display_ellipsis_p = true;
}
+ else /* Should never happen; but if it does, exit the loop. */
+ endpos = len;
}
while (invis != 0 && endpos < len);
}
else
{
- IT_STRING_CHARPOS (*it) = XFASTINT (end_charpos);
+ IT_STRING_CHARPOS (*it) = endpos;
compute_string_pos (&it->current.string_pos, old, it->string);
}
}
IT_BYTEPOS (*it) = CHAR_TO_BYTE (newpos);
}
+ if (display_ellipsis_p)
+ {
+ /* Make sure that the glyphs of the ellipsis will get
+ correct `charpos' values. If we would not update
+ it->position here, the glyphs would belong to the
+ last visible character _before_ the invisible
+ text, which confuses `set_cursor_from_row'.
+
+ We use the last invisible position instead of the
+ first because this way the cursor is always drawn on
+ the first "." of the ellipsis, whenever PT is inside
+ the invisible text. Otherwise the cursor would be
+ placed _after_ the ellipsis when the point is after the
+ first invisible character. */
+ if (!STRINGP (it->object))
+ {
+ it->position.charpos = newpos - 1;
+ it->position.bytepos = CHAR_TO_BYTE (it->position.charpos);
+ }
+ }
+
/* If there are before-strings at the start of invisible
text, and the text is invisible because of a text
property, arrange to show before-strings because 20.x did
}
else if (display_ellipsis_p)
{
- /* Make sure that the glyphs of the ellipsis will get
- correct `charpos' values. If we would not update
- it->position here, the glyphs would belong to the
- last visible character _before_ the invisible
- text, which confuses `set_cursor_from_row'.
-
- We use the last invisible position instead of the
- first because this way the cursor is always drawn on
- the first "." of the ellipsis, whenever PT is inside
- the invisible text. Otherwise the cursor would be
- placed _after_ the ellipsis when the point is after the
- first invisible character. */
- if (!STRINGP (it->object))
- {
- it->position.charpos = newpos - 1;
- it->position.bytepos = CHAR_TO_BYTE (it->position.charpos);
- }
it->ellipsis_p = true;
/* Let the ellipsis display before
considering any properties of the following char.
if (it->saved_face_id < 0 || it->saved_face_id != it->face_id)
it->saved_face_id = it->face_id = DEFAULT_FACE_ID;
+ /* If the ellipsis represents buffer text, it means we advanced in
+ the buffer, so we should no longer ignore overlay strings. */
+ if (it->method == GET_FROM_BUFFER)
+ it->ignore_overlay_strings_at_pos_p = false;
+
it->method = GET_FROM_DISPLAY_VECTOR;
it->ellipsis_p = true;
}
if (!NILP (form) && !EQ (form, Qt))
{
ptrdiff_t count = SPECPDL_INDEX ();
- struct gcpro gcpro1;
/* Bind `object' to the object having the `display' property, a
buffer or string. Bind `position' to the position in the
specbind (Qobject, object);
specbind (Qposition, make_number (CHARPOS (*position)));
specbind (Qbuffer_position, make_number (bufpos));
- GCPRO1 (form);
form = safe_eval (form);
- UNGCPRO;
unbind_to (count, Qnil);
}
{
struct face *face = FACE_FROM_ID (it->f, it->face_id);
it->voffset = - (XFLOATINT (value)
- * (FONT_HEIGHT (face->font)));
+ * (normal_char_height (face->font, -1)));
}
#endif /* HAVE_WINDOW_SYSTEM */
}
{
start_pos = *position;
*position = display_prop_end (it, object, start_pos);
+ /* If the display property comes from an overlay, don't consider
+ any potential stop_charpos values before the end of that
+ overlay. Since display_prop_end will happily find another
+ 'display' property coming from some other overlay or text
+ property on buffer positions before this overlay's end, we
+ need to ignore them, or else we risk displaying this
+ overlay's display string/image twice. */
+ if (!NILP (overlay))
+ {
+ ptrdiff_t ovendpos = OVERLAY_POSITION (OVERLAY_END (overlay));
+
+ if (ovendpos > CHARPOS (*position))
+ SET_TEXT_POS (*position, ovendpos, CHAR_TO_BYTE (ovendpos));
+ }
}
value = Qnil;
&& it->stop_charpos <= it->end_charpos));
it->current.overlay_string_index = -1;
it->n_overlay_strings = 0;
- it->overlay_strings_charpos = -1;
/* If there's an empty display string on the stack, pop the
stack, to resync the bidi iterator with IT's position. Such
empty strings are pushed onto the stack in
/* If we're at the end of the buffer, record that we have
processed the overlay strings there already, so that
next_element_from_buffer doesn't try it again. */
- if (NILP (it->string) && IT_CHARPOS (*it) >= it->end_charpos)
+ if (NILP (it->string)
+ && IT_CHARPOS (*it) >= it->end_charpos
+ && it->overlay_strings_charpos >= it->end_charpos)
it->overlay_strings_at_end_processed_p = true;
+ /* Note: we reset overlay_strings_charpos only here, to make
+ sure the just-processed overlays were indeed at EOB.
+ Otherwise, overlays on text with invisible text property,
+ which are processed with IT's position past the invisible
+ text, might fool us into thinking the overlays at EOB were
+ already processed (linum-mode can cause this, for
+ example). */
+ it->overlay_strings_charpos = -1;
}
else
{
case GET_FROM_STRETCH:
p->u.stretch.object = it->object;
break;
+ case GET_FROM_BUFFER:
+ case GET_FROM_DISPLAY_VECTOR:
+ case GET_FROM_STRING:
+ case GET_FROM_C_STRING:
+ break;
+ default:
+ emacs_abort ();
}
p->position = position ? *position : it->position;
p->current = it->current;
{
struct iterator_stack_entry *p;
bool from_display_prop = it->from_disp_prop_p;
+ ptrdiff_t prev_pos = IT_CHARPOS (*it);
eassert (it->sp > 0);
--it->sp;
it->method = GET_FROM_BUFFER;
it->object = it->w->contents;
}
+ break;
+ case GET_FROM_C_STRING:
+ break;
+ default:
+ emacs_abort ();
}
it->end_charpos = p->end_charpos;
it->string_nchars = p->string_nchars;
&& IT_STRING_BYTEPOS (*it) == it->bidi_it.bytepos)
|| (CONSP (it->object) && it->method == GET_FROM_STRETCH));
}
+ /* If we move the iterator over text covered by a display property
+ to a new buffer position, any info about previously seen overlays
+ is no longer valid. */
+ if (from_display_prop && it->sp == 0 && CHARPOS (it->position) != prev_pos)
+ it->ignore_overlay_strings_at_pos_p = false;
}
return face_id;
}
+/* Forget the `escape-glyph' and `glyphless-char' faces. This should
+ be called before redisplaying windows, and when the frame's face
+ cache is freed. */
+void
+forget_escape_and_glyphless_faces (void)
+{
+ last_escape_glyph_frame = NULL;
+ last_escape_glyph_face_id = (1 << FACE_ID_BITS);
+ last_glyphless_glyph_frame = NULL;
+ last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
+}
+
/* Load IT's display element fields with information about the next
display element from the current position of IT. Value is false if
end of buffer (or C string) is reached. */
non-ASCII spaces and hyphens specially. */
if (! ASCII_CHAR_P (c) && ! NILP (Vnobreak_char_display))
{
- if (c == 0xA0)
+ if (c == NO_BREAK_SPACE)
nonascii_space_p = true;
- else if (c == 0xAD || c == 0x2010 || c == 0x2011)
+ else if (c == SOFT_HYPHEN || c == HYPHEN
+ || c == NON_BREAKING_HYPHEN)
nonascii_hyphen_p = true;
}
if (CHAR_BYTE8_P (c))
/* Display \200 instead of \17777600. */
c = CHAR_TO_BYTE8 (c);
- len = sprintf (str, "%03o", c);
+ len = sprintf (str, "%03o", c + 0u);
XSETINT (it->ctl_chars[0], escape_glyph);
for (i = 0; i < len; i++)
treating terminal frames specially here. */
if (!FRAME_WINDOW_P (it->f))
- move_it_vertically (it, target_y - (it->current_y + line_height));
+ move_it_vertically (it, target_y - it->current_y);
else
{
do
Messages
***********************************************************************/
+/* Return the number of arguments the format string FORMAT needs. */
+
+static ptrdiff_t
+format_nargs (char const *format)
+{
+ ptrdiff_t nargs = 0;
+ for (char const *p = format; (p = strchr (p, '%')); p++)
+ if (p[1] == '%')
+ p++;
+ else
+ nargs++;
+ return nargs;
+}
-/* Add a message with format string FORMAT and arguments ARG1 and ARG2
+/* Add a message with format string FORMAT and formatted arguments
to *Messages*. */
void
-add_to_log (const char *format, Lisp_Object arg1, Lisp_Object arg2)
+add_to_log (const char *format, ...)
{
- Lisp_Object msg, fmt;
- char *buffer;
- ptrdiff_t len;
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
- USE_SAFE_ALLOCA;
-
- fmt = msg = Qnil;
- GCPRO4 (fmt, msg, arg1, arg2);
-
- fmt = build_string (format);
- msg = CALLN (Fformat, fmt, arg1, arg2);
+ va_list ap;
+ va_start (ap, format);
+ vadd_to_log (format, ap);
+ va_end (ap);
+}
- len = SBYTES (msg) + 1;
- buffer = SAFE_ALLOCA (len);
+void
+vadd_to_log (char const *format, va_list ap)
+{
+ ptrdiff_t form_nargs = format_nargs (format);
+ ptrdiff_t nargs = 1 + form_nargs;
+ Lisp_Object args[10];
+ eassert (nargs <= ARRAYELTS (args));
+ AUTO_STRING (args0, format);
+ args[0] = args0;
+ for (ptrdiff_t i = 1; i <= nargs; i++)
+ args[i] = va_arg (ap, Lisp_Object);
+ Lisp_Object msg = Qnil;
+ msg = Fformat_message (nargs, args);
+
+ ptrdiff_t len = SBYTES (msg) + 1;
+ USE_SAFE_ALLOCA;
+ char *buffer = SAFE_ALLOCA (len);
memcpy (buffer, SDATA (msg), len);
- message_dolog (buffer, len - 1, true, false);
+ message_dolog (buffer, len - 1, true, STRING_MULTIBYTE (msg));
SAFE_FREE ();
-
- UNGCPRO;
}
ptrdiff_t point_at_end = 0;
ptrdiff_t zv_at_end = 0;
Lisp_Object old_deactivate_mark;
- struct gcpro gcpro1;
old_deactivate_mark = Vdeactivate_mark;
oldbuf = current_buffer;
set_marker_restricted_both (oldbegv, Qnil, BEGV, BEGV_BYTE);
oldzv = message_dolog_marker3;
set_marker_restricted_both (oldzv, Qnil, ZV, ZV_BYTE);
- GCPRO1 (old_deactivate_mark);
if (PT == Z)
point_at_end = 1;
TEMP_SET_PT_BOTH (marker_position (oldpoint),
marker_byte_position (oldpoint));
- UNGCPRO;
unchain_marker (XMARKER (oldpoint));
unchain_marker (XMARKER (oldbegv));
unchain_marker (XMARKER (oldzv));
void
message3 (Lisp_Object m)
{
- struct gcpro gcpro1;
-
- GCPRO1 (m);
clear_message (true, true);
cancel_echoing ();
message_dolog (buffer, nbytes, true, multibyte);
SAFE_FREE ();
}
- message3_nolog (m);
-
- UNGCPRO;
+ if (! inhibit_message)
+ message3_nolog (m);
}
+/* Log the message M to stderr. Log an empty line if M is not a string. */
+
+static void
+message_to_stderr (Lisp_Object m)
+{
+ if (noninteractive_need_newline)
+ {
+ noninteractive_need_newline = false;
+ fputc ('\n', stderr);
+ }
+ if (STRINGP (m))
+ {
+ Lisp_Object s = ENCODE_SYSTEM (m);
+ fwrite (SDATA (s), SBYTES (s), 1, stderr);
+ }
+ if (!cursor_in_echo_area)
+ fputc ('\n', stderr);
+ fflush (stderr);
+}
/* The non-logging version of message3.
This does not cancel echoing, because it is used for echoing.
struct frame *sf = SELECTED_FRAME ();
if (FRAME_INITIAL_P (sf))
- {
- if (noninteractive_need_newline)
- putc ('\n', stderr);
- noninteractive_need_newline = false;
- if (STRINGP (m))
- {
- Lisp_Object s = ENCODE_SYSTEM (m);
-
- fwrite (SDATA (s), SBYTES (s), 1, stderr);
- }
- if (!cursor_in_echo_area)
- fprintf (stderr, "\n");
- fflush (stderr);
- }
+ message_to_stderr (m);
/* Error messages get reported properly by cmd_error, so this must be just an
informative message; if the frame hasn't really been initialized yet, just
toss it. */
{
CHECK_STRING (string);
+ bool need_message;
if (noninteractive)
- {
- if (m)
- {
- /* ENCODE_SYSTEM below can GC and/or relocate the
- Lisp data, so make sure we don't use it here. */
- eassert (relocatable_string_data_p (m) != 1);
-
- if (noninteractive_need_newline)
- putc ('\n', stderr);
- noninteractive_need_newline = false;
- fprintf (stderr, m, SDATA (ENCODE_SYSTEM (string)));
- if (!cursor_in_echo_area)
- fprintf (stderr, "\n");
- fflush (stderr);
- }
- }
- else if (INTERACTIVE)
+ need_message = !!m;
+ else if (!INTERACTIVE)
+ need_message = false;
+ else
{
/* The frame whose minibuffer we're going to display the message on.
It may be larger than the selected frame, so we need
/* Error messages get reported properly by cmd_error, so this must be
just an informative message; if the frame hasn't really been
initialized yet, just toss it. */
- if (f->glyphs_initialized_p)
- {
- struct gcpro gcpro1, gcpro2;
-
- Lisp_Object fmt = build_string (m);
- Lisp_Object msg = string;
- GCPRO2 (fmt, msg);
+ need_message = f->glyphs_initialized_p;
+ }
- msg = CALLN (Fformat, fmt, msg);
+ if (need_message)
+ {
+ AUTO_STRING (fmt, m);
+ Lisp_Object msg = CALLN (Fformat_message, fmt, string);
+ if (noninteractive)
+ message_to_stderr (msg);
+ else
+ {
if (log)
message3 (msg);
else
message3_nolog (msg);
- UNGCPRO;
-
/* Print should start at the beginning of the message
buffer next time. */
message_buf_print = false;
/* Dump an informative message to the minibuf. If M is 0, clear out
- any existing message, and let the mini-buffer text show through. */
+ any existing message, and let the mini-buffer text show through.
+
+ The message must be safe ASCII and the format must not contain ` or
+ '. If your message and format do not fit into this category,
+ convert your arguments to Lisp objects and use Fmessage instead. */
static void ATTRIBUTE_FORMAT_PRINTF (1, 0)
vmessage (const char *m, va_list ap)
}
-#if false
-/* The non-logging version of message. */
-
-void
-message_nolog (const char *m, ...)
-{
- Lisp_Object old_log_max;
- va_list ap;
- va_start (ap, m);
- old_log_max = Vmessage_log_max;
- Vmessage_log_max = Qnil;
- vmessage (m, ap);
- Vmessage_log_max = old_log_max;
- va_end (ap);
-}
-#endif
-
-
/* Display the current message in the current mini-buffer. This is
only called from error handlers in process.c, and is not time
critical. */
Lisp_Object window;
struct text_pos start;
+ /* We are about to enter redisplay without going through
+ redisplay_internal, so we need to forget these faces by hand
+ here. */
+ forget_escape_and_glyphless_faces ();
+
/* Do this before displaying, so that we have a large enough glyph
matrix for the display. If we can't get enough space for the
whole text, display the last N lines. That works by setting w->start. */
}
-/* Redisplay the echo area of the selected frame. If UPDATE_FRAME_P,
- update selected_frame. Value is true if the mini-windows height
- has been changed. */
+/* Redisplay the echo area of the selected frame. If UPDATE_FRAME_P, update
+ selected_frame. */
-static bool
+static void
echo_area_display (bool update_frame_p)
{
Lisp_Object mini_window;
/* Don't display if frame is invisible or not yet initialized. */
if (!FRAME_VISIBLE_P (f) || !f->glyphs_initialized_p)
- return false;
+ return;
#ifdef HAVE_WINDOW_SYSTEM
/* When Emacs starts, selected_frame may be the initial terminal
frame. If we let this through, a message would be displayed on
the terminal. */
if (FRAME_INITIAL_P (XFRAME (selected_frame)))
- return false;
+ return;
#endif /* HAVE_WINDOW_SYSTEM */
/* Redraw garbaged frames. */
pending input. */
ptrdiff_t count = SPECPDL_INDEX ();
specbind (Qredisplay_dont_pause, Qt);
- windows_or_buffers_changed = 44;
+ fset_redisplay (f);
redisplay_internal ();
unbind_to (count, Qnil);
}
if (EQ (mini_window, selected_window))
CHARPOS (this_line_start_pos) = 0;
- return window_height_changed_p;
+ if (window_height_changed_p)
+ {
+ fset_redisplay (f);
+
+ /* If window configuration was changed, frames may have been
+ marked garbaged. Clear them or we will experience
+ surprises wrt scrolling.
+ FIXME: How/why/when? */
+ clear_garbaged_frames ();
+ }
}
/* True if W's buffer was changed but not saved. */
{
bool all_windows = windows_or_buffers_changed || update_mode_lines;
bool some_windows = REDISPLAY_SOME_P ();
- struct gcpro gcpro1, gcpro2;
Lisp_Object tooltip_frame;
#ifdef HAVE_WINDOW_SYSTEM
/* Clear flag first in case we get an error below. */
FRAME_WINDOW_SIZES_CHANGED (f) = false;
functions = Vwindow_size_change_functions;
- GCPRO2 (tail, functions);
while (CONSP (functions))
{
call1 (XCAR (functions), frame);
functions = XCDR (functions);
}
- UNGCPRO;
}
- GCPRO1 (tail);
menu_bar_hooks_run = update_menu_bar (f, false, menu_bar_hooks_run);
#ifdef HAVE_WINDOW_SYSTEM
update_tool_bar (f, false);
#endif
- UNGCPRO;
}
unbind_to (count, Qnil);
ptrdiff_t count = SPECPDL_INDEX ();
Lisp_Object frame, new_tool_bar;
int new_n_tool_bar;
- struct gcpro gcpro1;
/* Set current_buffer to the buffer of the selected
window of the frame, so that we get the right local
specbind (Qoverriding_local_map, Qnil);
}
- GCPRO1 (new_tool_bar);
-
/* We must temporarily set the selected frame to this frame
before calling tool_bar_items, because the calculation of
the tool-bar keymap uses the selected frame (see
unblock_input ();
}
- UNGCPRO;
-
unbind_to (count, Qnil);
set_buffer_internal_1 (prev);
}
build_desired_tool_bar_string (struct frame *f)
{
int i, size, size_needed;
- struct gcpro gcpro1, gcpro2;
Lisp_Object image, plist;
image = plist = Qnil;
- GCPRO2 (image, plist);
/* Prepare F->desired_tool_bar_string. If we can reuse it, do so.
Otherwise, make a new string. */
else
{
AUTO_LIST4 (props, Qdisplay, Qnil, Qmenu_item, Qnil);
- struct gcpro gcpro1;
- GCPRO1 (props);
Fremove_text_properties (make_number (0), make_number (size),
props, f->desired_tool_bar_string);
- UNGCPRO;
}
/* Put a `display' property on the string for the images to display,
image = Fcons (Qimage, plist);
AUTO_LIST4 (props, Qdisplay, image, Qmenu_item,
make_number (i * TOOL_BAR_ITEM_NSLOTS));
- struct gcpro gcpro1;
- GCPRO1 (props);
/* Let the last image hide all remaining spaces in the tool bar
string. The string can be longer than needed when we reuse a
end = i + 1;
Fadd_text_properties (make_number (i), make_number (end),
props, f->desired_tool_bar_string);
- UNGCPRO;
#undef PROP
}
-
- UNGCPRO;
}
/* True means redisplay has to redisplay the miniwindow. */
bool update_miniwindow_p = false;
+ /* True means we need to redraw frames whose 'redisplay' bit is set. */
+ bool consider_some_frames_p = false;
+
TRACE ((stderr, "redisplay_internal %d\n", redisplaying_p));
/* No redisplay if running in batch mode or frame is not yet fully
sw = w;
pending = false;
- last_escape_glyph_frame = NULL;
- last_escape_glyph_face_id = (1 << FACE_ID_BITS);
- last_glyphless_glyph_frame = NULL;
- last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
+ forget_escape_and_glyphless_faces ();
+
+ inhibit_free_realized_faces = false;
+
+ consider_some_frames_p = false;
/* If face_change, init_iterator will free all realized faces, which
includes the faces referenced from current matrices. So, we
if (f->fonts_changed)
{
adjust_frame_glyphs (f);
+ /* Disable all redisplay optimizations for this frame.
+ This is because adjust_frame_glyphs resets the
+ enabled_p flag for all glyph rows of all windows, so
+ many optimizations will fail anyway, and some might
+ fail to test that flag and do bogus things as
+ result. */
+ SET_FRAME_GARBAGED (f);
f->fonts_changed = false;
}
/* If cursor type has been changed on the frame
other than selected, consider all frames. */
if (f != sf && f->cursor_type_changed)
- update_mode_lines = 31;
+ fset_redisplay (f);
}
clear_desired_matrices (f);
}
echo-area doesn't show through. */
&& !MINI_WINDOW_P (XWINDOW (selected_window))))
{
- bool window_height_changed_p = echo_area_display (false);
+ echo_area_display (false);
if (message_cleared_p)
update_miniwindow_p = true;
the echo area. */
if (!display_last_displayed_message_p)
message_cleared_p = false;
-
- if (window_height_changed_p)
- {
- windows_or_buffers_changed = 50;
-
- /* If window configuration was changed, frames may have been
- marked garbaged. Clear them or we will experience
- surprises wrt scrolling. */
- clear_garbaged_frames ();
- }
}
else if (EQ (selected_window, minibuf_window)
&& (current_buffer->clip_changed || window_outdated (w))
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))))
+#define AINC(a,i) \
+ { \
+ Lisp_Object entry = Fgethash (make_number (i), a, make_number (0)); \
+ if (INTEGERP (entry)) \
+ Fputhash (make_number (i), make_number (1 + XINT (entry)), a); \
+ }
AINC (Vredisplay__all_windows_cause, windows_or_buffers_changed);
AINC (Vredisplay__mode_lines_cause, update_mode_lines);
&& FRAME_VISIBLE_P (XFRAME (w->frame))
&& !FRAME_OBSCURED_P (XFRAME (w->frame))
&& !XFRAME (w->frame)->cursor_type_changed
+ && !XFRAME (w->frame)->face_change
+ && !XFRAME (w->frame)->redisplay
/* Make sure recorded data applies to current buffer, etc. */
&& this_line_buffer == current_buffer
&& match_p
#endif
/* Build desired matrices, and update the display. If
- consider_all_windows_p, do it for all windows on all frames.
- Otherwise do it for selected_window, only. */
+ consider_all_windows_p, do it for all windows on all frames. If
+ a frame's 'redisplay' flag is set, do it for all windows on each
+ such frame. Otherwise do it for selected_window, only. */
- if (consider_all_windows_p)
+ if (!consider_all_windows_p)
{
FOR_EACH_FRAME (tail, frame)
- XFRAME (frame)->updated_p = false;
+ {
+ if (XFRAME (frame)->redisplay
+ && XFRAME (frame) != sf
+ && !FRAME_INITIAL_P (XFRAME (frame)))
+ {
+ consider_some_frames_p = true;
+ break;
+ }
+ }
+ }
+
+ if (consider_all_windows_p || consider_some_frames_p)
+ {
+ FOR_EACH_FRAME (tail, frame)
+ {
+ if (XFRAME (frame)->redisplay || consider_all_windows_p)
+ XFRAME (frame)->updated_p = false;
+ }
propagate_buffer_redisplay ();
&& !EQ (FRAME_TTY (f)->top_frame, frame))
continue;
- retry_frame:
-
-#if defined (HAVE_WINDOW_SYSTEM) && !defined (USE_GTK) && !defined (HAVE_NS)
- /* Redisplay internal tool bar if this is the first time so we
- can adjust the frame height right now, if necessary. */
- if (!f->tool_bar_redisplayed_once)
- {
- if (redisplay_tool_bar (f))
- adjust_frame_glyphs (f);
- f->tool_bar_redisplayed_once = true;
- }
-#endif
+ if (!consider_all_windows_p && !f->redisplay)
+ continue;
+ retry_frame:
if (FRAME_WINDOW_P (f) || FRAME_TERMCAP_P (f) || f == sf)
{
bool gcscrollbars
if (f->fonts_changed)
{
adjust_frame_glyphs (f);
+ /* Disable all redisplay optimizations for this
+ frame. For the reasons, see the comment near
+ the previous call to adjust_frame_glyphs above. */
+ SET_FRAME_GARBAGED (f);
f->fonts_changed = false;
goto retry_frame;
}
if (sf->fonts_changed)
goto retry;
+ /* Prevent freeing of realized faces, since desired matrices are
+ pending that reference the faces we computed and cached. */
+ inhibit_free_realized_faces = true;
+
/* Prevent various kinds of signals during display update.
stdio is not robust about handling signals,
which can cause an apparent I/O error. */
RESTORE_IT (&it, &it, it1data);
move_it_by_lines (&it, 1);
SAVE_IT (it1, it, it1data);
- } while (line_bottom_y (&it1) - start_y < amount_to_scroll);
+ } while (IT_CHARPOS (it) < ZV
+ && line_bottom_y (&it1) - start_y < amount_to_scroll);
+ bidi_unshelve_cache (it1data, true);
}
/* If STARTP is unchanged, move it down another screen line. */
- if (CHARPOS (it.current.pos) == CHARPOS (startp))
+ if (IT_CHARPOS (it) == CHARPOS (startp))
move_it_by_lines (&it, 1);
startp = it.current.pos;
}
&& !update_mode_lines
&& !windows_or_buffers_changed
&& !f->cursor_type_changed
+ && !f->redisplay
&& NILP (Vshow_trailing_whitespace)
/* This code is not used for mini-buffer for the sake of the case
of redisplaying to replace an echo area message; since in
&& REDISPLAY_SOME_P ()
&& !w->redisplay
&& !w->update_mode_line
+ && !f->face_change
&& !f->redisplay
&& !buffer->text->redisplay
&& BUF_PT (buffer) == w->last_point)
/* Don't try to reuse the display if windows have been split
or such. */
|| windows_or_buffers_changed
+ || f->redisplay
|| f->cursor_type_changed)
return false;
#if false
#define GIVE_UP(X) \
do { \
- fprintf (stderr, "try_window_id give up %d\n", (X)); \
+ TRACE ((stderr, "try_window_id give up %d\n", (X))); \
return 0; \
} while (false)
#else
GIVE_UP (1);
/* This flag is used to prevent redisplay optimizations. */
- if (windows_or_buffers_changed || f->cursor_type_changed)
+ if (windows_or_buffers_changed || f->cursor_type_changed || f->redisplay)
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);
+ GIVE_UP (200);
/* Verify that narrowing has not changed.
Also verify that we were not told to prevent redisplay optimizations.
&& NILP (BVAR (XBUFFER (w->contents), bidi_paragraph_direction)))
GIVE_UP (22);
+ /* Give up if the buffer has line-spacing set, as Lisp-level changes
+ to that variable require thorough redisplay. */
+ if (!NILP (BVAR (XBUFFER (w->contents), extra_line_spacing)))
+ GIVE_UP (23);
+
/* Make sure beg_unchanged and end_unchanged are up to date. Do it
only if buffer has really changed. The reason is that the gap is
initially at Z for freshly visited files. The code below would
struct text_pos saved_pos;
Lisp_Object saved_object;
struct face *face;
+ struct glyph *g;
saved_object = it->object;
saved_pos = it->position;
PRODUCE_GLYPHS (it);
+#ifdef HAVE_WINDOW_SYSTEM
+ /* Make sure this space glyph has the right ascent and
+ descent values, or else cursor at end of line will look
+ funny, and height of empty lines will be incorrect. */
+ g = it->glyph_row->glyphs[TEXT_AREA] + n;
+ struct font *font = face->font ? face->font : FRAME_FONT (it->f);
+ if (n == 0)
+ {
+ Lisp_Object height, total_height;
+ int extra_line_spacing = it->extra_line_spacing;
+ int boff = font->baseline_offset;
+
+ if (font->vertical_centering)
+ boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+
+ it->object = saved_object; /* get_it_property needs this */
+ normal_char_ascent_descent (font, -1, &it->ascent, &it->descent);
+ /* Must do a subset of line height processing from
+ x_produce_glyph for newline characters. */
+ height = get_it_property (it, Qline_height);
+ if (CONSP (height)
+ && CONSP (XCDR (height))
+ && NILP (XCDR (XCDR (height))))
+ {
+ total_height = XCAR (XCDR (height));
+ height = XCAR (height);
+ }
+ else
+ total_height = Qnil;
+ height = calc_line_height_property (it, height, font, boff, true);
+
+ if (it->override_ascent >= 0)
+ {
+ it->ascent = it->override_ascent;
+ it->descent = it->override_descent;
+ boff = it->override_boff;
+ }
+ if (EQ (height, Qt))
+ extra_line_spacing = 0;
+ else
+ {
+ Lisp_Object spacing;
+
+ it->phys_ascent = it->ascent;
+ it->phys_descent = it->descent;
+ if (!NILP (height)
+ && XINT (height) > it->ascent + it->descent)
+ it->ascent = XINT (height) - it->descent;
+
+ if (!NILP (total_height))
+ spacing = calc_line_height_property (it, total_height, font,
+ boff, false);
+ else
+ {
+ spacing = get_it_property (it, Qline_spacing);
+ spacing = calc_line_height_property (it, spacing, font,
+ boff, false);
+ }
+ if (INTEGERP (spacing))
+ {
+ extra_line_spacing = XINT (spacing);
+ if (!NILP (total_height))
+ extra_line_spacing -= (it->phys_ascent + it->phys_descent);
+ }
+ }
+ if (extra_line_spacing > 0)
+ {
+ it->descent += extra_line_spacing;
+ if (extra_line_spacing > it->max_extra_line_spacing)
+ it->max_extra_line_spacing = extra_line_spacing;
+ }
+ it->max_ascent = it->ascent;
+ it->max_descent = it->descent;
+ /* Make sure compute_line_metrics recomputes the row height. */
+ it->glyph_row->height = 0;
+ }
+
+ g->ascent = it->max_ascent;
+ g->descent = it->max_descent;
+#endif
+
it->override_ascent = -1;
it->constrain_row_ascent_descent_p = false;
it->current_x = saved_x;
eassert (it->method == GET_FROM_BUFFER
|| it->method == GET_FROM_DISPLAY_VECTOR
- || it->method == GET_FROM_STRING);
+ || it->method == GET_FROM_STRING
+ || it->method == GET_FROM_IMAGE);
/* We need to save the current buffer/string position, so it will be
restored by pop_it, because iterate_out_of_display_property
Strong directional characters `L', `R', and `AL' can have their
intrinsic directionality overridden by directional override
-control characters RLO \(u+202e) and LRO \(u+202d). See the
+control characters RLO (u+202e) and LRO (u+202d). See the
function `get-char-code-property' for a way to inquire about
the `bidi-class' property of a character. */)
(Lisp_Object from, Lisp_Object to, Lisp_Object object)
/* Setup the arena. */
SET_TEXT_POS (pt, PT, PT_BYTE);
start_display (&it, w, pt);
+ /* When lines are truncated, we could be called with point
+ outside of the windows edges, in which case move_it_*
+ functions either prematurely stop at window's edge or jump to
+ the next screen line, whereas we rely below on our ability to
+ reach point, in order to start from its X coordinate. So we
+ need to disregard the window's horizontal extent in that case. */
+ if (it.line_wrap == TRUNCATE)
+ it.last_visible_x = INFINITY;
if (it.cmp_it.id < 0
&& it.method == GET_FROM_STRING
if (pt_x > 0)
{
start_display (&it, w, pt);
+ if (it.line_wrap == TRUNCATE)
+ it.last_visible_x = INFINITY;
reseat_at_previous_visible_line_start (&it);
it.current_x = it.current_y = it.hpos = 0;
if (pt_vpos != 0)
if (it.current_x != target_x)
move_it_in_display_line_to (&it, ZV, target_x, MOVE_TO_POS | MOVE_TO_X);
- /* When lines are truncated, the above loop will stop at the
- window edge. But we want to get to the end of line, even if
- it is beyond the window edge; automatic hscroll will then
- scroll the window to show point as appropriate. */
- if (target_is_eol_p && it.line_wrap == TRUNCATE
- && get_next_display_element (&it))
- {
- struct text_pos new_pos = it.current.pos;
-
- while (!ITERATOR_AT_END_OF_LINE_P (&it))
- {
- set_iterator_to_next (&it, false);
- if (it.method == GET_FROM_BUFFER)
- new_pos = it.current.pos;
- if (!get_next_display_element (&it))
- break;
- }
-
- it.current.pos = new_pos;
- }
-
/* If we ended up in a display string that covers point, move to
buffer position to the right in the visual order. */
if (dir > 0)
#ifdef HAVE_WINDOW_SYSTEM
if (EQ (prop, Qheight))
- return OK_PIXELS (font ? FONT_HEIGHT (font) : FRAME_LINE_HEIGHT (it->f));
+ return OK_PIXELS (font
+ ? normal_char_height (font, -1)
+ : FRAME_LINE_HEIGHT (it->f));
if (EQ (prop, Qwidth))
- return OK_PIXELS (font ? FONT_WIDTH (font) : FRAME_COLUMN_WIDTH (it->f));
+ return OK_PIXELS (font
+ ? FONT_WIDTH (font)
+ : FRAME_COLUMN_WIDTH (it->f));
#else
if (EQ (prop, Qheight) || EQ (prop, Qwidth))
return OK_PIXELS (1);
prop = Qnil;
}
- if (INTEGERP (prop) || FLOATP (prop))
+ if (NUMBERP (prop))
{
int base_unit = (width_p
? FRAME_COLUMN_WIDTH (it->f)
car = Qnil;
}
- if (INTEGERP (car) || FLOATP (car))
+ if (NUMBERP (car))
{
double fact;
pixels = XFLOATINT (car);
return false;
}
+void
+get_font_ascent_descent (struct font *font, int *ascent, int *descent)
+{
+#ifdef HAVE_WINDOW_SYSTEM
+ normal_char_ascent_descent (font, -1, ascent, descent);
+#else
+ *ascent = 1;
+ *descent = 0;
+#endif
+}
+
\f
/***********************************************************************
Glyph Display
return &metrics;
}
+/* A subroutine that computes "normal" values of ASCENT and DESCENT
+ for FONT. Values are taken from font-global ones, except for fonts
+ that claim preposterously large values, but whose glyphs actually
+ have reasonable dimensions. C is the character to use for metrics
+ if the font-global values are too large; if C is negative, the
+ function selects a default character. */
+static void
+normal_char_ascent_descent (struct font *font, int c, int *ascent, int *descent)
+{
+ *ascent = FONT_BASE (font);
+ *descent = FONT_DESCENT (font);
+
+ if (FONT_TOO_HIGH (font))
+ {
+ XChar2b char2b;
+
+ /* Get metrics of C, defaulting to a reasonably sized ASCII
+ character. */
+ if (get_char_glyph_code (c >= 0 ? c : '{', font, &char2b))
+ {
+ struct font_metrics *pcm = get_per_char_metric (font, &char2b);
+
+ if (!(pcm->width == 0 && pcm->rbearing == 0 && pcm->lbearing == 0))
+ {
+ /* We add 1 pixel to character dimensions as heuristics
+ that produces nicer display, e.g. when the face has
+ the box attribute. */
+ *ascent = pcm->ascent + 1;
+ *descent = pcm->descent + 1;
+ }
+ }
+ }
+}
+
+/* A subroutine that computes a reasonable "normal character height"
+ for fonts that claim preposterously large vertical dimensions, but
+ whose glyphs are actually reasonably sized. C is the character
+ whose metrics to use for those fonts, or -1 for default
+ character. */
+static int
+normal_char_height (struct font *font, int c)
+{
+ int ascent, descent;
+
+ normal_char_ascent_descent (font, c, &ascent, &descent);
+
+ return ascent + descent;
+}
+
/* EXPORT for RIF:
Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
frame F. Overhangs of glyphs other than type CHAR_GLYPH are
zero_width_ok_p = true;
width = (int)tem;
}
-#ifdef HAVE_WINDOW_SYSTEM
- else if (FRAME_WINDOW_P (it->f)
- && (prop = Fplist_get (plist, QCrelative_width), NUMVAL (prop) > 0))
+ else if (prop = Fplist_get (plist, QCrelative_width), NUMVAL (prop) > 0)
{
/* Relative width `:relative-width FACTOR' specified and valid.
Compute the width of the characters having the `glyph'
it2.glyph_row = NULL;
it2.what = IT_CHARACTER;
- x_produce_glyphs (&it2);
+ PRODUCE_GLYPHS (&it2);
width = NUMVAL (prop) * it2.pixel_width;
}
-#endif /* HAVE_WINDOW_SYSTEM */
else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
&& calc_pixel_width_or_height (&tem, it, prop, font, true,
&align_to))
/* Compute height. */
if (FRAME_WINDOW_P (it->f))
{
+ int default_height = normal_char_height (font, ' ');
+
if ((prop = Fplist_get (plist, QCheight), !NILP (prop))
&& calc_pixel_width_or_height (&tem, it, prop, font, false, 0))
{
}
else if (prop = Fplist_get (plist, QCrelative_height),
NUMVAL (prop) > 0)
- height = FONT_HEIGHT (font) * NUMVAL (prop);
+ height = default_height * NUMVAL (prop);
else
- height = FONT_HEIGHT (font);
+ height = default_height;
if (height <= 0 && (height < 0 || !zero_height_ok_p))
height = 1;
boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
}
- ascent = FONT_BASE (font) + boff;
- descent = FONT_DESCENT (font) - boff;
+ normal_char_ascent_descent (font, -1, &ascent, &descent);
if (override)
{
ASCII face. */
face = FACE_FROM_ID (it->f, it->face_id)->ascii_face;
font = face->font ? face->font : FRAME_FONT (it->f);
- it->ascent = FONT_BASE (font) + font->baseline_offset;
- it->descent = FONT_DESCENT (font) - font->baseline_offset;
+ normal_char_ascent_descent (font, -1, &it->ascent, &it->descent);
+ it->ascent += font->baseline_offset;
+ it->descent -= font->baseline_offset;
base_height = it->ascent + it->descent;
base_width = font->average_width;
else
{
eassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEX_CODE);
- sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c);
+ sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c + 0u);
str = buf;
}
for (len = 0; str[len] && ASCII_CHAR_P (str[len]) && len < 6; len++)
it->phys_ascent = pcm->ascent + boff;
it->phys_descent = pcm->descent - boff;
it->pixel_width = pcm->width;
+ /* Don't use font-global values for ascent and descent
+ if they result in an exceedingly large line height. */
+ if (it->override_ascent < 0)
+ {
+ if (FONT_TOO_HIGH (font))
+ {
+ it->ascent = it->phys_ascent;
+ it->descent = it->phys_descent;
+ /* These limitations are enforced by an
+ assertion near the end of this function. */
+ if (it->ascent < 0)
+ it->ascent = 0;
+ if (it->descent < 0)
+ it->descent = 0;
+ }
+ }
}
else
{
}
else
{
- it->ascent = FONT_BASE (font) + boff;
- it->descent = FONT_DESCENT (font) - boff;
+ if (FONT_TOO_HIGH (font))
+ {
+ it->ascent = font->pixel_size + boff - 1;
+ it->descent = -boff + 1;
+ if (it->descent < 0)
+ it->descent = 0;
+ }
+ else
+ {
+ it->ascent = FONT_BASE (font) + boff;
+ it->descent = FONT_DESCENT (font) - boff;
+ }
}
if (EQ (height, Qt))
it->pixel_width = next_tab_x - x;
it->nglyphs = 1;
- it->ascent = it->phys_ascent = FONT_BASE (font) + boff;
- it->descent = it->phys_descent = FONT_DESCENT (font) - boff;
+ if (FONT_TOO_HIGH (font))
+ {
+ if (get_char_glyph_code (' ', font, &char2b))
+ {
+ pcm = get_per_char_metric (font, &char2b);
+ if (pcm->width == 0
+ && pcm->rbearing == 0 && pcm->lbearing == 0)
+ pcm = NULL;
+ }
+
+ if (pcm)
+ {
+ it->ascent = pcm->ascent + boff;
+ it->descent = pcm->descent - boff;
+ }
+ else
+ {
+ it->ascent = font->pixel_size + boff - 1;
+ it->descent = -boff + 1;
+ }
+ if (it->ascent < 0)
+ it->ascent = 0;
+ if (it->descent < 0)
+ it->descent = 0;
+ }
+ else
+ {
+ it->ascent = FONT_BASE (font) + boff;
+ it->descent = FONT_DESCENT (font) - boff;
+ }
+ it->phys_ascent = it->ascent;
+ it->phys_descent = it->descent;
if (it->glyph_row)
{
it->nglyphs = 1;
}
}
+
+ if (FONT_TOO_HIGH (font))
+ {
+ int font_ascent, font_descent;
+
+ /* For very large fonts, where we ignore the declared font
+ dimensions, and go by per-character metrics instead,
+ don't let the row ascent and descent values (and the row
+ height computed from them) be smaller than the "normal"
+ character metrics. This avoids unpleasant effects
+ whereby lines on display would change their height
+ depending on which characters are shown. */
+ normal_char_ascent_descent (font, -1, &font_ascent, &font_descent);
+ it->max_ascent = max (it->max_ascent, font_ascent);
+ it->max_descent = max (it->max_descent, font_descent);
+ }
}
else if (it->what == IT_COMPOSITION && it->cmp_it.ch < 0)
{
boff = font->baseline_offset;
if (font->vertical_centering)
boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
- font_ascent = FONT_BASE (font) + boff;
- font_descent = FONT_DESCENT (font) - boff;
- font_height = FONT_HEIGHT (font);
+ normal_char_ascent_descent (font, -1, &font_ascent, &font_descent);
+ font_ascent += boff;
+ font_descent -= boff;
+ font_height = font_ascent + font_descent;
cmp->font = font;
Lisp_Object lr, lx0, ly0;
if (CONSP (circ)
&& CONSP (XCAR (circ))
- && (lr = XCDR (circ), INTEGERP (lr) || FLOATP (lr))
+ && (lr = XCDR (circ), NUMBERP (lr))
&& (lx0 = XCAR (XCAR (circ)), INTEGERP (lx0))
&& (ly0 = XCDR (XCAR (circ)), INTEGERP (ly0)))
{
define_frame_cursor1 (struct frame *f, Cursor cursor, Lisp_Object pointer)
{
/* Do not change cursor shape while dragging mouse. */
- if (!NILP (do_mouse_tracking))
+ if (EQ (do_mouse_tracking, Qdragging))
return;
if (!NILP (pointer))
}
/* Change the mouse face according to what is under X/Y. */
+ bool mouse_face_shown = false;
if (STRINGP (string))
{
mouse_face = Fget_text_property (pos, Qmouse_face, string);
glyph->face_id,
true);
show_mouse_face (hlinfo, DRAW_MOUSE_FACE);
+ mouse_face_shown = true;
if (NILP (pointer))
pointer = Qhand;
}
- else if ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))
- clear_mouse_face (hlinfo);
}
+
+ /* If mouse-face doesn't need to be shown, clear any existing
+ mouse-face. */
+ if ((area == ON_MODE_LINE || area == ON_HEADER_LINE) && !mouse_face_shown)
+ clear_mouse_face (hlinfo);
+
#ifdef HAVE_WINDOW_SYSTEM
if (FRAME_WINDOW_P (f))
define_frame_cursor1 (f, cursor, pointer);
/* Find the last one. */
last = first;
first_x = x;
- while (last < end
- && x < r->x + r->width)
+ /* Use a signed int intermediate value to avoid catastrophic
+ failures due to comparison between signed and unsigned, when
+ x is negative (can happen for wide images that are hscrolled). */
+ int r_end = r->x + r->width;
+ while (last < end && x < r_end)
{
x += last->pixel_width;
++last;
check later if it is changed. */
bool phys_cursor_on_p = w->phys_cursor_on_p;
+ /* Use a signed int intermediate value to avoid catastrophic
+ failures due to comparison between signed and unsigned, when
+ y0 or y1 is negative (can happen for tall images). */
+ int r_bottom = r.y + r.height;
+
/* Update lines intersecting rectangle R. */
first_overlapping_row = last_overlapping_row = NULL;
for (row = w->current_matrix->rows;
int y0 = row->y;
int y1 = MATRIX_ROW_BOTTOM_Y (row);
- if ((y0 >= r.y && y0 < r.y + r.height)
- || (y1 > r.y && y1 < r.y + r.height)
+ if ((y0 >= r.y && y0 < r_bottom)
+ || (y1 > r.y && y1 < r_bottom)
|| (r.y >= y0 && r.y < y1)
- || (r.y + r.height > y0 && r.y + r.height < y1))
+ || (r_bottom > y0 && r_bottom < y1))
{
/* A header line may be overlapping, but there is no need
to fix overlapping areas for them. KFS 2005-02-12 */
if (WINDOW_WANTS_MODELINE_P (w)
&& (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
row->enabled_p)
- && row->y < r.y + r.height)
+ && row->y < r_bottom)
{
if (expose_line (w, row, &r))
mouse_face_overwritten_p = true;
DEFSYM (Qredisplay_internal, "redisplay_internal (C function)");
+ DEFVAR_BOOL("inhibit-message", inhibit_message,
+ doc: /* Non-nil means calls to `message' are not displayed.
+They are still logged to the *Messages* buffer. */);
+ inhibit_message = 0;
+
message_dolog_marker1 = Fmake_marker ();
staticpro (&message_dolog_marker1);
message_dolog_marker2 = Fmake_marker ();
DEFSYM (Qcircle, "circle");
DEFSYM (Qpoly, "poly");
- /* The symbol `inhibit-menubar-update' and its DEFVAR_BOOL variable. */
DEFSYM (Qinhibit_menubar_update, "inhibit-menubar-update");
- DEFSYM (Qmessage_truncate_lines, "message-truncate-lines");
DEFSYM (Qgrow_only, "grow-only");
DEFSYM (Qinhibit_eval_during_redisplay, "inhibit-eval-during-redisplay");
DEFSYM (Qarrow, "arrow");
/* also Qtext */
+ DEFSYM (Qdragging, "dragging");
+
DEFSYM (Qinhibit_free_realized_faces, "inhibit-free-realized-faces");
list_of_error = list1 (list2 (Qerror, Qvoid_variable));
DEFVAR_LISP ("frame-title-format", Vframe_title_format,
doc: /* Template for displaying the title bar of visible frames.
-\(Assuming the window manager supports this feature.)
+(Assuming the window manager supports this feature.)
This variable has the same structure as `mode-line-format', except that
the %c and %l constructs are ignored. It is used only on frames for
-which no explicit name has been set \(see `modify-frame-parameters'). */);
+which no explicit name has been set (see `modify-frame-parameters'). */);
DEFVAR_LISP ("icon-title-format", Vicon_title_format,
doc: /* Template for displaying the title bar of an iconified frame.
-\(Assuming the window manager supports this feature.)
+(Assuming the window manager supports this feature.)
This variable has the same structure as `mode-line-format' (which see),
and is used only on frames for which no explicit name has been set
-\(see `modify-frame-parameters'). */);
+(see `modify-frame-parameters'). */);
Vicon_title_format
= Vframe_title_format
= listn (CONSTYPE_PURE, 3,
window is autoselected only after the mouse has remained in that
window for the duration of the delay.
A negative number has a similar effect, but causes windows to be
-autoselected only after the mouse has stopped moving. \(Because of
+autoselected only after the mouse has stopped moving. (Because of
the way Emacs compares mouse events, you will occasionally wait twice
-that time before the window gets selected.\)
+that time before the window gets selected.)
Any other value means to autoselect window instantaneously when the
mouse pointer enters it.
DEFVAR_LISP ("redisplay--all-windows-cause", Vredisplay__all_windows_cause,
doc: /* */);
- Vredisplay__all_windows_cause
- = Fmake_vector (make_number (100), make_number (0));
+ Vredisplay__all_windows_cause = Fmake_hash_table (0, NULL);
DEFVAR_LISP ("redisplay--mode-lines-cause", Vredisplay__mode_lines_cause,
doc: /* */);
- Vredisplay__mode_lines_cause
- = Fmake_vector (make_number (100), make_number (0));
+ Vredisplay__mode_lines_cause = Fmake_hash_table (0, NULL);
}