/* Display generation from window structure and buffer text.
-Copyright (C) 1985-1988, 1993-1995, 1997-2015 Free Software Foundation,
+Copyright (C) 1985-1988, 1993-1995, 1997-2016 Free Software Foundation,
Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
#include "font.h"
#include "fontset.h"
#include "blockinput.h"
+#include "xwidget.h"
#ifdef HAVE_WINDOW_SYSTEM
#include TERM_HEADER
#endif /* HAVE_WINDOW_SYSTEM */
void
maybe_set_redisplay (Lisp_Object symbol)
{
- if (!NILP (Fassoc_string (symbol, Vredisplay__variables, Qnil)))
+ if (HASH_TABLE_P (Vredisplay__variables)
+ && hash_lookup (XHASH_TABLE (Vredisplay__variables), symbol, NULL) >= 0)
{
bset_update_mode_line (current_buffer);
current_buffer->prevent_redisplay_optimizations_p = true;
static bool set_cursor_from_row (struct window *, struct glyph_row *,
struct glyph_matrix *, ptrdiff_t, ptrdiff_t,
int, int);
+static bool cursor_row_fully_visible_p (struct window *, bool, bool);
static bool update_menu_bar (struct frame *, bool, bool);
static bool try_window_reusing_current_matrix (struct window *);
static int try_window_id (struct window *);
static bool next_element_from_composition (struct it *);
static bool next_element_from_image (struct it *);
static bool next_element_from_stretch (struct it *);
+static bool next_element_from_xwidget (struct it *);
static void load_overlay_strings (struct it *, ptrdiff_t);
static bool get_next_display_element (struct it *);
static enum move_it_result
if (CHARPOS (top) > ZV)
SET_TEXT_POS (top, BEGV, BEGV_BYTE);
+ /* If the top of the window is after CHARPOS, the latter is surely
+ not visible. */
+ if (charpos >= 0 && CHARPOS (top) > charpos)
+ return visible_p;
+
/* Compute exact mode line heights. */
if (WINDOW_WANTS_MODELINE_P (w))
w->mode_line_height
cache and mode line face are not yet initialized. */
if (FRAME_FACE_CACHE (f))
{
- struct face *face = FACE_FROM_ID (f, face_id);
+ struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
if (face)
{
if (face->font)
ascent = row->ascent;
if (row->ascent < glyph->ascent)
{
- y =- glyph->ascent - row->ascent;
+ y -= glyph->ascent - row->ascent;
ascent = glyph->ascent;
}
/* If we have a boxed mode line, make the first character appear
with a left box line. */
- face = FACE_FROM_ID (it->f, remapped_base_face_id);
+ face = FACE_FROM_ID_OR_NULL (it->f, remapped_base_face_id);
if (face && face->box != FACE_NO_BOX)
it->start_of_box_run_p = true;
}
character properties needed for reordering are not yet
available. */
it->bidi_p =
- NILP (Vpurify_flag)
+ !redisplay__inhibit_bidi
&& !NILP (BVAR (current_buffer, bidi_display_reordering))
&& it->multibyte_p;
{
struct face *new_face = FACE_FROM_ID (it->f, new_face_id);
/* If it->face_id is -1, old_face below will be NULL, see
- the definition of FACE_FROM_ID. This will happen if this
- is the initial call that gets the face. */
- struct face *old_face = FACE_FROM_ID (it->f, it->face_id);
+ the definition of FACE_FROM_ID_OR_NULL. This will happen
+ if this is the initial call that gets the face. */
+ struct face *old_face = FACE_FROM_ID_OR_NULL (it->f, it->face_id);
/* If the value of face_id of the iterator is -1, we have to
look in front of IT's position and see whether there is a
{
int prev_face_id = face_before_it_pos (it);
- old_face = FACE_FROM_ID (it->f, prev_face_id);
+ old_face = FACE_FROM_ID_OR_NULL (it->f, prev_face_id);
}
/* If the new face has a box, but the old face does not,
if (new_face_id != it->face_id)
{
struct face *new_face = FACE_FROM_ID (it->f, new_face_id);
- struct face *old_face = FACE_FROM_ID (it->f, it->face_id);
+ struct face *old_face = FACE_FROM_ID_OR_NULL (it->f, it->face_id);
/* If new face has a box but old face hasn't, this is the
start of a run of characters with box, i.e. it has a
it->current.dpvec_index = 0;
it->dpvec_face_id = -1;
- /* Remember the current face id in case glyphs specify faces.
- IT's face is restored in set_iterator_to_next.
- saved_face_id was set to preceding char's face in handle_stop. */
- if (it->saved_face_id < 0 || it->saved_face_id != it->face_id)
- it->saved_face_id = it->face_id = DEFAULT_FACE_ID;
+ /* Use IT->saved_face_id for the ellipsis, so that it has the same
+ face as the preceding text. IT->saved_face_id was set in
+ handle_stop to the face of the preceding character, and will be
+ different from IT->face_id only if the invisible text skipped in
+ handle_invisible_prop has some non-default face on its first
+ character. We thus ignore the face of the invisible text when we
+ display the ellipsis. IT's face is restored in set_iterator_to_next. */
+ if (it->saved_face_id >= 0)
+ it->face_id = it->saved_face_id;
/* If the ellipsis represents buffer text, it means we advanced in
the buffer, so we should no longer ignore overlay strings. */
if (CONSP (spec)
/* Simple specifications. */
&& !EQ (XCAR (spec), Qimage)
+#ifdef HAVE_XWIDGETS
+ && !EQ (XCAR (spec), Qxwidget)
+#endif
&& !EQ (XCAR (spec), Qspace)
&& !EQ (XCAR (spec), Qwhen)
&& !EQ (XCAR (spec), Qslice)
it->font_height = XCAR (XCDR (spec));
if (!NILP (it->font_height))
{
- struct face *face = FACE_FROM_ID (it->f, it->face_id);
int new_height = -1;
if (CONSP (it->font_height)
{
/* Call function with current height as argument.
Value is the new height. */
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
Lisp_Object height;
height = safe_call1 (it->font_height,
face->lface[LFACE_HEIGHT_INDEX]);
/* Evaluate IT->font_height with `height' bound to the
current specified height to get the new height. */
ptrdiff_t count = SPECPDL_INDEX ();
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
specbind (Qheight, face->lface[LFACE_HEIGHT_INDEX]);
value = safe_eval (it->font_height);
|| EQ (XCAR (spec), Qright_fringe))
&& CONSP (XCDR (spec)))
{
- int fringe_bitmap;
-
if (it)
{
if (!FRAME_WINDOW_P (it->f))
#ifdef HAVE_WINDOW_SYSTEM
value = XCAR (XCDR (spec));
- if (!SYMBOLP (value)
- || !(fringe_bitmap = lookup_fringe_bitmap (value)))
+ int fringe_bitmap = SYMBOLP (value) ? lookup_fringe_bitmap (value) : 0;
+ if (! fringe_bitmap)
/* If we return here, POSITION has been advanced
across the text with this property. */
{
|| ((it ? FRAME_WINDOW_P (it->f) : frame_window_p)
&& valid_image_p (value))
#endif /* not HAVE_WINDOW_SYSTEM */
- || (CONSP (value) && EQ (XCAR (value), Qspace)));
+ || (CONSP (value) && EQ (XCAR (value), Qspace))
+ || ((it ? FRAME_WINDOW_P (it->f) : frame_window_p)
+ && valid_xwidget_spec_p (value)));
if (valid_p && display_replaced == 0)
{
*position = it->position = start_pos;
retval = 1 + (it->area == TEXT_AREA);
}
+ else if (valid_xwidget_spec_p (value))
+ {
+ it->what = IT_XWIDGET;
+ it->method = GET_FROM_XWIDGET;
+ it->position = start_pos;
+ it->object = NILP (object) ? it->w->contents : object;
+ *position = start_pos;
+ it->xwidget = lookup_xwidget (value);
+ }
#ifdef HAVE_WINDOW_SYSTEM
else
{
case GET_FROM_STRETCH:
p->u.stretch.object = it->object;
break;
+ case GET_FROM_XWIDGET:
+ p->u.xwidget.object = it->object;
+ break;
case GET_FROM_BUFFER:
case GET_FROM_DISPLAY_VECTOR:
case GET_FROM_STRING:
it->object = p->u.image.object;
it->slice = p->u.image.slice;
break;
+ case GET_FROM_XWIDGET:
+ it->object = p->u.xwidget.object;
+ break;
case GET_FROM_STRETCH:
it->object = p->u.stretch.object;
break;
break;
case GET_FROM_STRING:
{
- struct face *face = FACE_FROM_ID (it->f, it->face_id);
+ struct face *face = FACE_FROM_ID_OR_NULL (it->f, it->face_id);
/* Restore the face_box_p flag, since it could have been
overwritten by the face of the object that we just finished
loading loadup.el, as the necessary character property tables are
not yet available. */
it->bidi_p =
- NILP (Vpurify_flag)
+ !redisplay__inhibit_bidi
&& !NILP (BVAR (&buffer_defaults, bidi_display_reordering));
if (s == NULL)
next_element_from_string,
next_element_from_c_string,
next_element_from_image,
- next_element_from_stretch
+ next_element_from_stretch,
+ next_element_from_xwidget,
};
#define GET_NEXT_DISPLAY_ELEMENT(it) (*get_next_element[(it)->method]) (it)
|| ((IT)->cmp_it.stop_pos == (CHARPOS) \
&& composition_reseat_it (&(IT)->cmp_it, CHARPOS, BYTEPOS, \
END_CHARPOS, (IT)->w, \
- FACE_FROM_ID ((IT)->f, (IT)->face_id), \
+ FACE_FROM_ID_OR_NULL ((IT)->f, \
+ (IT)->face_id), \
(IT)->string)))
goto display_control;
}
+ /* Handle non-ascii hyphens in the mode where it only
+ gets highlighting. */
+
+ if (nonascii_hyphen_p && EQ (Vnobreak_char_display, Qt))
+ {
+ /* Merge `nobreak-space' into the current face. */
+ face_id = merge_faces (it->f, Qnobreak_hyphen, 0,
+ it->face_id);
+ XSETINT (it->ctl_chars[0], '-');
+ ctl_len = 1;
+ goto display_control;
+ }
+
/* Handle sequences that start with the "escape glyph". */
/* the default escape glyph is \. */
? merge_faces (it->f, Qt, lface_id, it->face_id)
: merge_escape_glyph_face (it));
- /* Draw non-ASCII hyphen with just highlighting: */
-
- if (nonascii_hyphen_p && EQ (Vnobreak_char_display, Qt))
- {
- XSETINT (it->ctl_chars[0], '-');
- ctl_len = 1;
- goto display_control;
- }
-
/* Draw non-ASCII space/hyphen with escape glyph: */
if (nonascii_space_p || nonascii_hyphen_p)
if (it->method == GET_FROM_STRING && it->sp)
{
int face_id = underlying_face_id (it);
- struct face *face = FACE_FROM_ID (it->f, face_id);
+ struct face *face = FACE_FROM_ID_OR_NULL (it->f, face_id);
if (face)
{
{
ptrdiff_t ignore;
int next_face_id;
+ bool text_from_string = false;
+ /* Normally, the next buffer location is stored in
+ IT->current.pos... */
struct text_pos pos = it->current.pos;
- /* For a string from a display property, the next
- buffer position is stored in the 'position'
+ /* ...but for a string from a display property, the
+ next buffer position is stored in the 'position'
member of the iteration stack slot below the
current one, see handle_single_display_spec. By
- contrast, it->current.pos was is not yet updated
- to point to that buffer position; that will
- happen in pop_it, after we finish displaying the
- current string. Note that we already checked
- above that it->sp is positive, so subtracting one
- from it is safe. */
+ contrast, it->current.pos was not yet updated to
+ point to that buffer position; that will happen
+ in pop_it, after we finish displaying the current
+ string. Note that we already checked above that
+ it->sp is positive, so subtracting one from it is
+ safe. */
if (it->from_disp_prop_p)
- pos = (it->stack + it->sp - 1)->position;
+ {
+ int stackp = it->sp - 1;
+
+ /* Find the stack level with data from buffer. */
+ while (stackp >= 0
+ && STRINGP ((it->stack + stackp)->string))
+ stackp--;
+ if (stackp < 0)
+ {
+ /* If no stack slot was found for iterating
+ a buffer, we are displaying text from a
+ string, most probably the mode line or
+ the header line, and that string has a
+ display string on some of its
+ characters. */
+ text_from_string = true;
+ pos = it->stack[it->sp - 1].position;
+ }
+ else
+ pos = (it->stack + stackp)->position;
+ }
else
INC_TEXT_POS (pos, it->multibyte_p);
- if (CHARPOS (pos) >= ZV)
+ if (text_from_string)
+ {
+ Lisp_Object base_string = it->stack[it->sp - 1].string;
+
+ if (CHARPOS (pos) >= SCHARS (base_string) - 1)
+ it->end_of_box_run_p = true;
+ else
+ {
+ next_face_id
+ = face_at_string_position (it->w, base_string,
+ CHARPOS (pos), 0,
+ &ignore, face_id, false);
+ it->end_of_box_run_p
+ = (FACE_FROM_ID (it->f, next_face_id)->box
+ == FACE_NO_BOX);
+ }
+ }
+ else if (CHARPOS (pos) >= ZV)
it->end_of_box_run_p = true;
else
{
- next_face_id = face_at_buffer_position
- (it->w, CHARPOS (pos), &ignore,
- CHARPOS (pos) + TEXT_PROP_DISTANCE_LIMIT, false, -1);
+ next_face_id =
+ face_at_buffer_position (it->w, CHARPOS (pos), &ignore,
+ CHARPOS (pos)
+ + TEXT_PROP_DISTANCE_LIMIT,
+ false, -1);
it->end_of_box_run_p
= (FACE_FROM_ID (it->f, next_face_id)->box
== FACE_NO_BOX);
case GET_FROM_IMAGE:
case GET_FROM_STRETCH:
+ case GET_FROM_XWIDGET:
+
/* The position etc with which we have to proceed are on
the stack. The position may be at the end of a string,
if the `display' property takes up the whole string. */
/* Glyphs in the display vector could have the box face, so we
need to set the related flags in the iterator, as
appropriate. */
- this_face = FACE_FROM_ID (it->f, it->face_id);
- prev_face = FACE_FROM_ID (it->f, prev_face_id);
+ this_face = FACE_FROM_ID_OR_NULL (it->f, it->face_id);
+ prev_face = FACE_FROM_ID_OR_NULL (it->f, prev_face_id);
/* Is this character the first character of a box-face run? */
it->start_of_box_run_p = (this_face && this_face->box != FACE_NO_BOX
it->saved_face_id);
}
}
- next_face = FACE_FROM_ID (it->f, next_face_id);
+ next_face = FACE_FROM_ID_OR_NULL (it->f, next_face_id);
it->end_of_box_run_p = (this_face && this_face->box != FACE_NO_BOX
&& (!next_face
|| next_face->box == FACE_NO_BOX));
return true;
}
+static bool
+next_element_from_xwidget (struct it *it)
+{
+ it->what = IT_XWIDGET;
+ return true;
+}
+
/* Fill iterator IT with next display element from a stretch glyph
property. IT->object is the value of the text property. Value is
void *ppos_data = NULL;
bool may_wrap = false;
enum it_method prev_method = it->method;
- ptrdiff_t closest_pos IF_LINT (= 0), prev_pos = IT_CHARPOS (*it);
+ ptrdiff_t closest_pos UNINIT;
+ ptrdiff_t prev_pos = IT_CHARPOS (*it);
bool saw_smaller_pos = prev_pos < to_charpos;
/* Don't produce glyphs in produce_glyphs. */
&& it->dpvec + it->current.dpvec_index + 1 >= it->dpend)))
/* If there's a line-/wrap-prefix, handle it. */
- if (it->hpos == 0 && it->method == GET_FROM_BUFFER
- && it->current_y < it->last_visible_y)
+ if (it->hpos == 0 && it->method == GET_FROM_BUFFER)
handle_line_prefix (it);
if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos))
? WINDOW_LEFT_FRINGE_WIDTH (it->w)
: WINDOW_RIGHT_FRINGE_WIDTH (it->w)))))
{
+ bool moved_forward = false;
+
if (/* IT->hpos == 0 means the very first glyph
doesn't fit on the line, e.g. a wide image. */
it->hpos == 0
now that we know it fits in this row. */
if (BUFFER_POS_REACHED_P ())
{
+ bool can_wrap = true;
+
+ /* If we are at a whitespace character
+ that barely fits on this screen line,
+ but the next character is also
+ whitespace, we cannot wrap here. */
+ if (it->line_wrap == WORD_WRAP
+ && wrap_it.sp >= 0
+ && may_wrap
+ && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+ {
+ struct it tem_it;
+ void *tem_data = NULL;
+
+ SAVE_IT (tem_it, *it, tem_data);
+ set_iterator_to_next (it, true);
+ if (get_next_display_element (it)
+ && IT_DISPLAYING_WHITESPACE (it))
+ can_wrap = false;
+ RESTORE_IT (it, &tem_it, tem_data);
+ }
if (it->line_wrap != WORD_WRAP
|| wrap_it.sp < 0
- /* If we've just found whitespace to
- wrap, effectively ignore the
- previous wrap point -- it is no
- longer relevant, but we won't
- have an opportunity to update it,
- since we've reached the edge of
- this screen line. */
- || (may_wrap
+ /* If we've just found whitespace
+ where we can wrap, effectively
+ ignore the previous wrap point --
+ it is no longer relevant, but we
+ won't have an opportunity to
+ update it, since we've reached
+ the edge of this screen line. */
+ || (may_wrap && can_wrap
&& IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)))
{
it->hpos = hpos_before_this_char;
result = MOVE_POS_MATCH_OR_ZV;
break;
}
+ moved_forward = true;
if (BUFFER_POS_REACHED_P ())
{
if (ITERATOR_AT_END_OF_LINE_P (it))
longer relevant, but we won't have an opportunity
to update it, since we are done with this screen
line. */
- if (may_wrap && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+ if (may_wrap && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)
+ /* If the character after the one which set the
+ may_wrap flag is also whitespace, we can't
+ wrap here, since the screen line cannot be
+ wrapped in the middle of whitespace.
+ Therefore, wrap_it _is_ relevant in that
+ case. */
+ && !(moved_forward && IT_DISPLAYING_WHITESPACE (it)))
{
/* If we've found TO_X, go back there, as we now
know the last word fits on this screen line. */
}
else
result = MOVE_NEWLINE_OR_CR;
+ /* If we've processed the newline, make sure this flag is
+ reset, as it must only be set when the newline itself is
+ processed. */
+ if (result == MOVE_NEWLINE_OR_CR)
+ it->constrain_row_ascent_descent_p = false;
break;
}
#undef BUFFER_POS_REACHED_P
- /* If we scanned beyond to_pos and didn't find a point to wrap at,
- restore the saved iterator. */
- if (atpos_it.sp >= 0)
+ /* If we scanned beyond TO_POS, restore the saved iterator either to
+ the wrap point (if found), or to atpos/atx location. We decide which
+ data to use to restore the saved iterator state by their X coordinates,
+ since buffer positions might increase non-monotonically with screen
+ coordinates due to bidi reordering. */
+ if (result == MOVE_LINE_CONTINUED
+ && it->line_wrap == WORD_WRAP
+ && wrap_it.sp >= 0
+ && ((atpos_it.sp >= 0 && wrap_it.current_x < atpos_it.current_x)
+ || (atx_it.sp >= 0 && wrap_it.current_x < atx_it.current_x)))
+ RESTORE_IT (it, &wrap_it, wrap_data);
+ else if (atpos_it.sp >= 0)
RESTORE_IT (it, &atpos_it, atpos_data);
else if (atx_it.sp >= 0)
RESTORE_IT (it, &atx_it, atx_data);
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
+If FROM is t, use the minimum accessible position that starts a
+non-empty line. 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.
+use the maximum accessible position that ends a non-empty line.
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. In any case, text whose x-coordinate
-is beyond X-LIMIT is ignored. Since calculating the width of long lines
-can take some time, it's always a good idea to make this argument as
-small as possible; in particular, if the buffer contains long lines that
-shall be truncated anyway.
+pixel-width of WINDOW's body; use this if you want to know how high
+WINDOW should be become in order to fit all of its buffer's text with
+the width of WINDOW unaltered. Use the maximum width WINDOW may assume
+if you intend to change WINDOW's width. In any case, text whose
+x-coordinate is beyond X-LIMIT is ignored. Since calculating the width
+of long lines can take some time, it's always a good idea to make this
+argument as small as possible; in particular, if the buffer contains
+long lines that shall be truncated anyway.
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.
+height (excluding the height of the mode- or header-line, if any) 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 large or 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
ptrdiff_t start, end, pos;
struct text_pos startp;
void *itdata = NULL;
- int c, max_y = -1, x = 0, y = 0;
+ int c, max_x = 0, max_y = 0, x = 0, y = 0;
CHECK_BUFFER (buffer);
b = XBUFFER (buffer);
end = max (start, min (XINT (to), ZV));
}
- if (!NILP (y_limit))
- {
- CHECK_NUMBER (y_limit);
- max_y = min (XINT (y_limit), INT_MAX);
- }
+ if (!NILP (x_limit) && RANGED_INTEGERP (0, x_limit, INT_MAX))
+ max_x = XINT (x_limit);
+
+ if (NILP (y_limit))
+ max_y = INT_MAX;
+ else if (RANGED_INTEGERP (0, y_limit, INT_MAX))
+ max_y = XINT (y_limit);
itdata = bidi_shelve_cache ();
SET_TEXT_POS (startp, start, CHAR_TO_BYTE (start));
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);
+ it.last_visible_x = max_x;
/* 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);
+ /* Don't return more than X-LIMIT. */
+ if (x > max_x)
+ x = max_x;
}
- y = it.current_y + it.max_ascent + it.max_descent;
+ /* Subtract height of header-line which was counted automatically by
+ start_display. */
+ y = it.current_y + it.max_ascent + it.max_descent
+ - WINDOW_HEADER_LINE_HEIGHT (w);
+ /* Don't return more than Y-LIMIT. */
+ if (y > max_y)
+ y = max_y;
- 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, Qheader_line)
+ || EQ (mode_and_header_line, Qt))
+ /* Re-add height of header-line as requested. */
+ 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. */
+ /* Add height of mode-line as requested. */
y = y + WINDOW_MODE_LINE_HEIGHT (w);
bidi_unshelve_cache (itdata, false);
}
if (STRINGP (m))
{
- Lisp_Object s = ENCODE_SYSTEM (m);
+ Lisp_Object coding_system = Vlocale_coding_system;
+ Lisp_Object s;
+
+ if (!NILP (Vcoding_system_for_write))
+ coding_system = Vcoding_system_for_write;
+ if (!NILP (coding_system))
+ s = code_convert_string_norecord (m, coding_system, true);
+ else
+ s = m;
+
fwrite (SDATA (s), SBYTES (s), 1, stderr);
}
if (!cursor_in_echo_area)
static void
ensure_echo_area_buffers (void)
{
- int i;
-
- for (i = 0; i < 2; ++i)
+ for (int i = 0; i < 2; i++)
if (!BUFFERP (echo_buffer[i])
|| !BUFFER_LIVE_P (XBUFFER (echo_buffer[i])))
{
- char name[30];
- Lisp_Object old_buffer;
- int j;
-
- old_buffer = echo_buffer[i];
- echo_buffer[i] = Fget_buffer_create
- (make_formatted_string (name, " *Echo Area %d*", i));
+ Lisp_Object old_buffer = echo_buffer[i];
+ static char const name_fmt[] = " *Echo Area %d*";
+ char name[sizeof name_fmt + INT_STRLEN_BOUND (int)];
+ AUTO_STRING_WITH_LEN (lname, name, sprintf (name, name_fmt, i));
+ echo_buffer[i] = Fget_buffer_create (lname);
bset_truncate_lines (XBUFFER (echo_buffer[i]), Qnil);
/* to force word wrap in echo area -
it was decided to postpone this*/
/* XBUFFER (echo_buffer[i])->word_wrap = Qt; */
- for (j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; j++)
if (EQ (old_buffer, echo_area_buffer[j]))
echo_area_buffer[j] = echo_buffer[i];
}
suitable buffer from echo_buffer[] and clear it.
If WHICH < 0, set echo_area_buffer[1] to echo_area_buffer[0], so
- that the current message becomes the last displayed one, make
- choose a suitable buffer for echo_area_buffer[0], and clear it.
+ that the current message becomes the last displayed one, choose a
+ suitable buffer for echo_area_buffer[0], and clear it.
Value is what FN returns. */
echo_area_buffer[this_one] = Qnil;
}
- /* Choose a suitable buffer from echo_buffer[] is we don't
+ /* Choose a suitable buffer from echo_buffer[] if we don't
have one. */
if (NILP (echo_area_buffer[this_one]))
{
reset the echo_area_buffer in question to nil at the end because
with_echo_area_buffer will sets it to an empty buffer. */
bool i = display_last_displayed_message_p;
+ /* According to the C99, C11 and C++11 standards, the integral value
+ of a "bool" is always 0 or 1, so this array access is safe here,
+ if oddly typed. */
no_message_p = NILP (echo_area_buffer[i]);
window_height_changed_p
if (frame_garbaged)
{
Lisp_Object tail, frame;
+ struct frame *sf = SELECTED_FRAME ();
FOR_EACH_FRAME (tail, frame)
{
if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f))
{
- if (f->resized_p)
+ if (f->resized_p
+ /* It makes no sense to redraw a non-selected TTY
+ frame, since that will actually clear the
+ selected frame, and might leave the selected
+ frame with corrupted display, if it happens not
+ to be marked garbaged. */
+ && !(f != sf && (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f))))
redraw_frame (f);
else
clear_current_matrices (f);
{
struct frame *f = XFRAME (frame);
- if (FRAME_WINDOW_P (f)
- || FRAME_MINIBUF_ONLY_P (f)
- || f->explicit_name)
+ if ((FRAME_WINDOW_P (f)
+ || FRAME_MINIBUF_ONLY_P (f)
+ || f->explicit_name)
+ && NILP (Fframe_parameter (frame, Qtooltip)))
{
/* Do we have more than one visible frame on this X display? */
Lisp_Object tail, other_frame, fmt;
&& !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))
- {
- Lisp_Object functions;
-
- /* Clear flag first in case we get an error below. */
- FRAME_WINDOW_SIZES_CHANGED (f) = false;
- functions = Vwindow_size_change_functions;
-
- while (CONSP (functions))
- {
- if (!EQ (XCAR (functions), Qt))
- call1 (XCAR (functions), frame);
- functions = XCDR (functions);
- }
- }
-
+ run_window_size_change_functions (frame);
menu_bar_hooks_run = update_menu_bar (f, false, menu_bar_hooks_run);
#ifdef HAVE_WINDOW_SYSTEM
update_tool_bar (f, false);
beginning of a paragraph, before the first strong directional
character, can change the base direction of the paragraph (unless
the buffer specifies a fixed paragraph direction), which will
- require to redisplay the whole paragraph. It might be worthwhile
+ require redisplaying the whole paragraph. It might be worthwhile
to find the paragraph limits and widen the range of redisplayed
lines to that, but for now just give up this optimization. */
if (!NILP (BVAR (XBUFFER (w->contents), bidi_display_reordering))
specbind (Qinhibit_free_realized_faces, Qnil);
/* Record this function, so it appears on the profiler's backtraces. */
- record_in_backtrace (Qredisplay_internal, 0, 0);
+ record_in_backtrace (Qredisplay_internal_xC_functionx, 0, 0);
FOR_EACH_FRAME (tail, frame)
XFRAME (frame)->already_hscrolled_p = false;
{
echo_area_display (false);
+ /* If echo_area_display resizes the mini-window, the redisplay and
+ window_sizes_changed flags of the selected frame are set, but
+ it's too late for the hooks in window-size-change-functions,
+ which have been examined already in prepare_menu_bars. So in
+ that case we call the hooks here only for the selected frame. */
+ if (sf->redisplay)
+ {
+ ptrdiff_t count1 = SPECPDL_INDEX ();
+
+ record_unwind_save_match_data ();
+ run_window_size_change_functions (selected_frame);
+ unbind_to (count1, Qnil);
+ }
+
if (message_cleared_p)
update_miniwindow_p = true;
&& (current_buffer->clip_changed || window_outdated (w))
&& resize_mini_window (w, false))
{
+ if (sf->redisplay)
+ {
+ ptrdiff_t count1 = SPECPDL_INDEX ();
+
+ record_unwind_save_match_data ();
+ run_window_size_change_functions (selected_frame);
+ unbind_to (count1, Qnil);
+ }
+
/* Resized active mini-window to fit the size of what it is
showing if its contents might have changed. */
must_finish = true;
eassert (this_line_vpos == it.vpos);
eassert (this_line_y == it.current_y);
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+ if (cursor_row_fully_visible_p (w, false, true))
+ {
#ifdef GLYPH_DEBUG
- *w->desired_matrix->method = 0;
- debug_method_add (w, "optimization 3");
+ *w->desired_matrix->method = 0;
+ debug_method_add (w, "optimization 3");
#endif
- goto update;
+ goto update;
+ }
+ else
+ goto cancel;
}
else
goto cancel;
}
else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
{
- Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf);
- struct frame *mini_frame;
-
displayed_buffer = XBUFFER (XWINDOW (selected_window)->contents);
/* Use list_of_error, not Qerror, so that
we catch only errors and don't run the debugger. */
list_of_error,
redisplay_window_error);
if (update_miniwindow_p)
- internal_condition_case_1 (redisplay_window_1, mini_window,
- list_of_error,
+ internal_condition_case_1 (redisplay_window_1,
+ FRAME_MINIBUF_WINDOW (sf), list_of_error,
redisplay_window_error);
/* Compare desired and current matrices, perform output. */
have put text on a frame other than the selected one, so the
above call to update_frame would not have caught it. Catch
it here. */
- mini_window = FRAME_MINIBUF_WINDOW (sf);
- mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
+ Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf);
+ struct frame *mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
if (mini_frame != sf && FRAME_WINDOW_P (mini_frame))
{
The new window start will be computed, based on W's width, starting
from the start of the continued line. It is the start of the
- screen line with the minimum distance from the old start W->start. */
+ screen line with the minimum distance from the old start W->start,
+ which is still before point (otherwise point will definitely not
+ be visible in the window). */
static bool
compute_window_start_on_continuation_line (struct window *w)
{
- struct text_pos pos, start_pos;
+ struct text_pos pos, start_pos, pos_before_pt;
bool window_start_changed_p = false;
SET_TEXT_POS_FROM_MARKER (start_pos, w->start);
reseat_at_previous_visible_line_start (&it);
/* 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))
+ say it takes too much time to compute a new window start.
+ Also, give up if the line start is after point, as in that
+ case point will not be visible with any window start we
+ compute. */
+ if (IT_CHARPOS (it) <= PT
+ || (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;
decreased, the new window start will be < the old start.
So, we're looking for the display line start with the
minimum distance from the old window start. */
- pos = it.current.pos;
+ pos_before_pt = pos = it.current.pos;
min_distance = INFINITY;
while ((distance = eabs (CHARPOS (start_pos) - IT_CHARPOS (it))),
distance < min_distance)
{
min_distance = distance;
+ if (CHARPOS (pos) <= PT)
+ pos_before_pt = pos;
pos = it.current.pos;
if (it.line_wrap == WORD_WRAP)
{
move_it_by_lines (&it, 1);
}
+ /* It makes very little sense to make the new window start
+ after point, as point won't be visible. If that's what
+ the loop above finds, fall back on the candidate before
+ or at point that is closest to the old window start. */
+ if (CHARPOS (pos) > PT)
+ pos = pos_before_pt;
+
/* Set the window start there. */
SET_MARKER_FROM_TEXT_POS (w->start, pos);
window_start_changed_p = true;
bool last_line_misfit = false;
ptrdiff_t beg_unchanged, end_unchanged;
int frame_line_height;
+ bool use_desired_matrix;
SET_TEXT_POS (lpoint, PT, PT_BYTE);
opoint = lpoint;
if (w->cursor.vpos < 0)
{
/* If point does not appear, try to move point so it does
- appear. The desired matrix has been built above, so we
- can use it here. */
- new_vpos = window_box_height (w) / 2;
+ appear. The desired matrix has been built above, so we
+ can use it here. First see if point is in invisible
+ text, and if so, move it to the first visible buffer
+ position past that. */
+ struct glyph_row *r = NULL;
+ Lisp_Object invprop =
+ get_char_property_and_overlay (make_number (PT), Qinvisible,
+ Qnil, NULL);
+
+ if (TEXT_PROP_MEANS_INVISIBLE (invprop) != 0)
+ {
+ ptrdiff_t alt_pt;
+ Lisp_Object invprop_end =
+ Fnext_single_char_property_change (make_number (PT), Qinvisible,
+ Qnil, Qnil);
+
+ if (NATNUMP (invprop_end))
+ alt_pt = XFASTINT (invprop_end);
+ else
+ alt_pt = ZV;
+ r = row_containing_pos (w, alt_pt, w->desired_matrix->rows,
+ NULL, 0);
+ }
+ if (r)
+ new_vpos = MATRIX_ROW_BOTTOM_Y (r);
+ else /* Give up and just move to the middle of the window. */
+ new_vpos = window_box_height (w) / 2;
}
if (!cursor_row_fully_visible_p (w, false, false))
startp = run_window_scroll_functions (window, it.current.pos);
/* Redisplay the window. */
+ use_desired_matrix = false;
if (!current_matrix_up_to_date_p
|| windows_or_buffers_changed
|| f->cursor_type_changed
|| MINI_WINDOW_P (w)
|| !(used_current_matrix_p
= try_window_reusing_current_matrix (w)))
- try_window (window, startp, 0);
+ use_desired_matrix = (try_window (window, startp, 0) == 1);
/* If new fonts have been loaded (due to fontsets), give up. We
have to start a new redisplay since we need to re-adjust glyph
and similar ones. */
if (w->cursor.vpos < 0)
{
+ /* Prefer the desired matrix to the current matrix, if possible,
+ in the fallback calculations below. This is because using
+ the current matrix might completely goof, e.g. if its first
+ row is after point. */
+ struct glyph_matrix *matrix =
+ use_desired_matrix ? w->desired_matrix : w->current_matrix;
/* First, try locating the proper glyph row for PT. */
struct glyph_row *row =
- row_containing_pos (w, PT, w->current_matrix->rows, NULL, 0);
+ row_containing_pos (w, PT, matrix->rows, NULL, 0);
/* Sometimes point is at the beginning of invisible text that is
before the 1st character displayed in the row. In that case,
alt_pos = XFASTINT (invis_end);
else
alt_pos = ZV;
- row = row_containing_pos (w, alt_pos, w->current_matrix->rows,
- NULL, 0);
+ row = row_containing_pos (w, alt_pos, matrix->rows, NULL, 0);
}
}
/* Finally, fall back on the first row of the window after the
displaying the cursor at all. */
if (!row)
{
- row = w->current_matrix->rows;
+ row = matrix->rows;
if (row->mode_line_p)
++row;
}
- set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+ set_cursor_from_row (w, row, matrix, 0, 0, 0, 0);
}
if (!cursor_row_fully_visible_p (w, false, false))
if (scroll_conservatively > SCROLL_LIMIT)
{
int window_total_lines
- = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) * frame_line_height;
+ = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
int margin =
scroll_margin > 0
? min (scroll_margin, window_total_lines / 4)
ignore_mouse_drag_p = true;
#endif
}
+ ptrdiff_t count1 = SPECPDL_INDEX ();
+ /* x_consider_frame_title calls select-frame, which calls
+ resize_mini_window, which could resize the mini-window and by
+ that undo the effect of this redisplay cycle wrt minibuffer
+ and echo-area display. Binding inhibit-redisplay to t makes
+ the call to resize_mini_window a no-op, thus avoiding the
+ adverse side effects. */
+ specbind (Qinhibit_redisplay, Qt);
x_consider_frame_title (w->frame);
+ unbind_to (count1, Qnil);
#endif
}
while (true)
{
/* Give up if we have gone too far. */
- if (end && row >= end)
+ if ((end && row >= end) || !row->enabled_p)
return NULL;
/* This formerly returned if they were equal.
I think that both quantities are of a "last plus one" type;
beginning of a paragraph, before the first strong directional
character, can change the base direction of the paragraph (unless
the buffer specifies a fixed paragraph direction), which will
- require to redisplay the whole paragraph. It might be worthwhile
+ require redisplaying the whole paragraph. It might be worthwhile
to find the paragraph limits and widen the range of redisplayed
lines to that, but for now just give up this optimization and
redisplay from scratch. */
eassert (MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row));
row = find_last_row_displaying_text (w->current_matrix, &it,
first_unchanged_at_end_row);
- eassert (row && MATRIX_ROW_DISPLAYS_TEXT_P (row));
+ eassume (row && MATRIX_ROW_DISPLAYS_TEXT_P (row));
adjust_window_ends (w, row, true);
eassert (w->window_end_bytepos >= 0);
IF_DEBUG (debug_method_add (w, "A"));
struct glyph_row *current_row = current_matrix->rows + vpos;
struct glyph_row *desired_row = desired_matrix->rows + vpos;
- for (row = NULL;
- row == NULL && vpos >= first_vpos;
- --vpos, --current_row, --desired_row)
+ for (row = NULL; !row; --vpos, --current_row, --desired_row)
{
+ eassert (first_vpos <= vpos);
if (desired_row->enabled_p)
{
if (MATRIX_ROW_DISPLAYS_TEXT_P (desired_row))
row = current_row;
}
- eassert (row != NULL);
w->window_end_vpos = vpos + 1;
w->window_end_pos = Z - MATRIX_ROW_END_CHARPOS (row);
w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
glyph->left_box_line_p,
glyph->right_box_line_p);
}
+ else if (glyph->type == XWIDGET_GLYPH)
+ {
+#ifndef HAVE_XWIDGETS
+ eassume (false);
+#else
+ fprintf (stderr,
+ " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+ glyph - row->glyphs[TEXT_AREA],
+ 'X',
+ glyph->charpos,
+ (BUFFERP (glyph->object)
+ ? 'B'
+ : (STRINGP (glyph->object)
+ ? 'S'
+ : '-')),
+ glyph->pixel_width,
+ glyph->u.xwidget,
+ '.',
+ glyph->face_id,
+ glyph->left_box_line_p,
+ glyph->right_box_line_p);
+#endif
+ }
}
struct text_pos saved_pos;
Lisp_Object saved_object;
struct face *face;
- struct glyph *g;
saved_object = it->object;
saved_pos = it->position;
/* 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 glyph *g = it->glyph_row->glyphs[TEXT_AREA] + n;
struct font *font = face->font ? face->font : FRAME_FONT (it->f);
if (n == 0)
{
return;
/* The default face, possibly remapped. */
- default_face = FACE_FROM_ID (f, lookup_basic_face (f, DEFAULT_FACE_ID));
+ default_face = FACE_FROM_ID_OR_NULL (f,
+ lookup_basic_face (f, DEFAULT_FACE_ID));
/* Face extension extends the background and box of IT->face_id
to the end of the line. If the background equals the background
of the frame, we don't have to do anything. */
- if (it->face_before_selective_p)
- face = FACE_FROM_ID (f, it->saved_face_id);
- else
- face = FACE_FROM_ID (f, it->face_id);
+ face = FACE_FROM_ID (f, (it->face_before_selective_p
+ ? it->saved_face_id
+ : it->face_id));
if (FRAME_WINDOW_P (f)
&& MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row)
struct it wrap_it;
void *wrap_data = NULL;
bool may_wrap = false;
- int wrap_x IF_LINT (= 0);
+ int wrap_x UNINIT;
int wrap_row_used = -1;
- int wrap_row_ascent IF_LINT (= 0), wrap_row_height IF_LINT (= 0);
- int wrap_row_phys_ascent IF_LINT (= 0), wrap_row_phys_height IF_LINT (= 0);
- int wrap_row_extra_line_spacing IF_LINT (= 0);
- ptrdiff_t wrap_row_min_pos IF_LINT (= 0), wrap_row_min_bpos IF_LINT (= 0);
- ptrdiff_t wrap_row_max_pos IF_LINT (= 0), wrap_row_max_bpos IF_LINT (= 0);
+ int wrap_row_ascent UNINIT, wrap_row_height UNINIT;
+ int wrap_row_phys_ascent UNINIT, wrap_row_phys_height UNINIT;
+ int wrap_row_extra_line_spacing UNINIT;
+ ptrdiff_t wrap_row_min_pos UNINIT, wrap_row_min_bpos UNINIT;
+ ptrdiff_t wrap_row_max_pos UNINIT, wrap_row_max_bpos UNINIT;
int cvpos;
ptrdiff_t min_pos = ZV + 1, max_pos = 0;
- ptrdiff_t min_bpos IF_LINT (= 0), max_bpos IF_LINT (= 0);
+ ptrdiff_t min_bpos UNINIT, max_bpos UNINIT;
bool pending_handle_line_prefix = false;
/* We always start displaying at hpos zero even if hscrolled. */
|| NILP (BVAR (buf, enable_multibyte_characters))
/* When we are loading loadup.el, the character property tables
needed for bidi iteration are not yet available. */
- || !NILP (Vpurify_flag))
+ || redisplay__inhibit_bidi)
return Qleft_to_right;
else if (!NILP (BVAR (buf, bidi_paragraph_direction)))
return BVAR (buf, bidi_paragraph_direction);
/* When we are loading loadup.el, the character property
tables needed for bidi iteration are not yet
available. */
- || !NILP (Vpurify_flag))
+ || redisplay__inhibit_bidi)
return Qnil;
validate_subarray (object, from, to, SCHARS (object), &from_pos, &to_pos);
/* When we are loading loadup.el, the character property
tables needed for bidi iteration are not yet
available. */
- || !NILP (Vpurify_flag))
+ || redisplay__inhibit_bidi)
return Qnil;
set_buffer_temp (buf);
}
/* Move to the target X coordinate. */
-#ifdef HAVE_WINDOW_SYSTEM
/* On GUI frames, as we don't know the X coordinate of the
character to the left of point, moving point to the left
requires walking, one grapheme cluster at a time, until we
new_pos.bytepos = CHAR_TO_BYTE (new_pos.charpos);
it.current.pos = new_pos;
}
- else
-#endif
- if (it.current_x != target_x)
+ else if (it.current_x != target_x)
move_it_in_display_line_to (&it, ZV, target_x, MOVE_TO_POS | MOVE_TO_X);
/* If we ended up in a display string that covers point, move to
return OK_PIXELS (width_p ? img->width : img->height);
}
+ if (FRAME_WINDOW_P (it->f) && valid_xwidget_spec_p (prop))
+ {
+ // TODO: Don't return dummy size.
+ return OK_PIXELS (100);
+ }
#endif
if (EQ (car, Qplus) || EQ (car, Qminus))
{
face = FACE_FROM_ID (f, glyph->face_id);
/* Make sure X resources of the face are allocated. */
- eassert (face != NULL);
prepare_face_for_display (f, face);
if (face->font)
}
+#ifdef HAVE_XWIDGETS
+static void
+fill_xwidget_glyph_string (struct glyph_string *s)
+{
+ eassert (s->first_glyph->type == XWIDGET_GLYPH);
+ s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
+ s->font = s->face->font;
+ s->width = s->first_glyph->pixel_width;
+ s->ybase += s->first_glyph->voffset;
+ s->xwidget = s->first_glyph->u.xwidget;
+}
+#endif
/* Fill glyph string S from a sequence of stretch glyphs.
START is the index of the first glyph to consider,
} \
while (false)
+#ifndef HAVE_XWIDGETS
+# define BUILD_XWIDGET_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ eassume (false)
+#else
+# define BUILD_XWIDGET_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ do \
+ { \
+ s = alloca (sizeof *s); \
+ INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL); \
+ fill_xwidget_glyph_string (s); \
+ append_glyph_string (&(HEAD), &(TAIL), s); \
+ ++(START); \
+ s->x = (X); \
+ } \
+ while (false)
+#endif
/* Add a glyph string for a sequence of character glyphs to the list
of strings between HEAD and TAIL. START is the index of the first
#define BUILD_COMPOSITE_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
do { \
int face_id = (row)->glyphs[area][START].face_id; \
- struct face *base_face = FACE_FROM_ID (f, face_id); \
+ struct face *base_face = FACE_FROM_ID (f, face_id); \
ptrdiff_t cmp_id = (row)->glyphs[area][START].u.cmp.id; \
struct composition *cmp = composition_table[cmp_id]; \
XChar2b *char2b; \
to allocate glyph strings (because draw_glyphs can be called
asynchronously). */
-#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
+#define BUILD_GLYPH_STRINGS_1(START, END, HEAD, TAIL, HL, X, LAST_X) \
do \
{ \
HEAD = TAIL = NULL; \
case IMAGE_GLYPH: \
BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
- break; \
- \
+ break;
+
+#define BUILD_GLYPH_STRINGS_XW(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ case XWIDGET_GLYPH: \
+ BUILD_XWIDGET_GLYPH_STRING (START, END, HEAD, TAIL, \
+ HL, X, LAST_X); \
+ break;
+
+#define BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X) \
case GLYPHLESS_GLYPH: \
BUILD_GLYPHLESS_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
\
default: \
- emacs_abort (); \
+ emacs_abort (); \
} \
\
if (s) \
} while (false)
+#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ BUILD_GLYPH_STRINGS_1(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ BUILD_GLYPH_STRINGS_XW(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X)
+
+
/* Draw glyphs between START and END in AREA of ROW on window W,
starting at x-position X. X is relative to AREA in W. HL is a
face-override with the following meaning:
{
struct glyph_string *h, *t;
Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
- int mouse_beg_col IF_LINT (= 0), mouse_end_col IF_LINT (= 0);
+ int mouse_beg_col UNINIT, mouse_end_col UNINIT;
bool check_mouse_face = false;
int dummy_x = 0;
glyph->object = it->object;
if (it->pixel_width > 0)
{
+ eassert (it->pixel_width <= SHRT_MAX);
glyph->pixel_width = it->pixel_width;
glyph->padding_p = false;
}
}
glyph->charpos = it->cmp_it.charpos;
glyph->object = it->object;
+ eassert (it->pixel_width <= SHRT_MAX);
glyph->pixel_width = it->pixel_width;
glyph->ascent = it->ascent;
glyph->descent = it->descent;
eassert (it->what == IT_IMAGE);
face = FACE_FROM_ID (it->f, it->face_id);
- eassert (face);
/* Make sure X resources of the face is loaded. */
prepare_face_for_display (it->f, face);
}
img = IMAGE_FROM_ID (it->f, it->image_id);
- eassert (img);
/* Make sure X resources of the image is loaded. */
prepare_image_for_display (it->f, img);
{
glyph->charpos = CHARPOS (it->position);
glyph->object = it->object;
- glyph->pixel_width = it->pixel_width;
+ glyph->pixel_width = clip_to_bounds (-1, it->pixel_width, SHRT_MAX);
glyph->ascent = glyph_ascent;
glyph->descent = it->descent;
glyph->voffset = it->voffset;
}
}
+static void
+produce_xwidget_glyph (struct it *it)
+{
+#ifdef HAVE_XWIDGETS
+ struct xwidget *xw;
+ int glyph_ascent, crop;
+ eassert (it->what == IT_XWIDGET);
+
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
+ /* Make sure X resources of the face is loaded. */
+ prepare_face_for_display (it->f, face);
+
+ xw = it->xwidget;
+ it->ascent = it->phys_ascent = glyph_ascent = xw->height/2;
+ it->descent = xw->height/2;
+ it->phys_descent = it->descent;
+ it->pixel_width = xw->width;
+ /* It's quite possible for images to have an ascent greater than
+ their height, so don't get confused in that case. */
+ if (it->descent < 0)
+ it->descent = 0;
+
+ it->nglyphs = 1;
+
+ if (face->box != FACE_NO_BOX)
+ {
+ if (face->box_line_width > 0)
+ {
+ it->ascent += face->box_line_width;
+ it->descent += face->box_line_width;
+ }
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += eabs (face->box_line_width);
+ it->pixel_width += eabs (face->box_line_width);
+ }
+
+ take_vertical_position_into_account (it);
+
+ /* Automatically crop wide image glyphs at right edge so we can
+ draw the cursor on same display row. */
+ crop = it->pixel_width - (it->last_visible_x - it->current_x);
+ if (crop > 0 && (it->hpos == 0 || it->pixel_width > it->last_visible_x / 4))
+ it->pixel_width -= crop;
+
+ if (it->glyph_row)
+ {
+ enum glyph_row_area area = it->area;
+ struct glyph *glyph
+ = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+
+ if (it->glyph_row->reversed_p)
+ {
+ struct glyph *g;
+
+ /* Make room for the new glyph. */
+ for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
+ g[1] = *g;
+ glyph = it->glyph_row->glyphs[it->area];
+ }
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = it->object;
+ glyph->pixel_width = clip_to_bounds (-1, it->pixel_width, SHRT_MAX);
+ glyph->ascent = glyph_ascent;
+ glyph->descent = it->descent;
+ glyph->voffset = it->voffset;
+ glyph->type = XWIDGET_GLYPH;
+ glyph->avoid_cursor_p = it->avoid_cursor_p;
+ glyph->multibyte_p = it->multibyte_p;
+ if (it->glyph_row->reversed_p && area == TEXT_AREA)
+ {
+ /* In R2L rows, the left and the right box edges need to be
+ drawn in reverse direction. */
+ glyph->right_box_line_p = it->start_of_box_run_p;
+ glyph->left_box_line_p = it->end_of_box_run_p;
+ }
+ else
+ {
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ }
+ glyph->overlaps_vertically_p = 0;
+ glyph->padding_p = 0;
+ glyph->glyph_not_available_p = 0;
+ glyph->face_id = it->face_id;
+ glyph->u.xwidget = it->xwidget;
+ glyph->font_type = FONT_TYPE_UNKNOWN;
+ if (it->bidi_p)
+ {
+ glyph->resolved_level = it->bidi_it.resolved_level;
+ eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
+ glyph->bidi_type = it->bidi_it.type;
+ }
+ ++it->glyph_row->used[area];
+ }
+ else
+ IT_EXPAND_MATRIX_WIDTH (it, area);
+ }
+#endif
+}
/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
of the glyph, WIDTH and HEIGHT are the width and height of the
}
glyph->charpos = CHARPOS (it->position);
glyph->object = object;
- glyph->pixel_width = width;
+ /* FIXME: It would be better to use TYPE_MAX here, but
+ __typeof__ is not portable enough... */
+ glyph->pixel_width = clip_to_bounds (-1, width, SHRT_MAX);
glyph->ascent = ascent;
glyph->descent = height - ascent;
glyph->voffset = it->voffset;
struct face *face;
face_id = lookup_named_face (it->f, face_name, false);
- if (face_id < 0)
- return make_number (-1);
-
- face = FACE_FROM_ID (it->f, face_id);
- font = face->font;
- if (font == NULL)
+ face = FACE_FROM_ID_OR_NULL (it->f, face_id);
+ if (face == NULL || ((font = face->font) == NULL))
return make_number (-1);
boff = font->baseline_offset;
if (font->vertical_centering)
}
glyph->charpos = CHARPOS (it->position);
glyph->object = it->object;
+ eassert (it->pixel_width <= SHRT_MAX);
glyph->pixel_width = it->pixel_width;
glyph->ascent = it->ascent;
glyph->descent = it->descent;
int leftmost, rightmost, lowest, highest;
int lbearing, rbearing;
int i, width, ascent, descent;
- int c IF_LINT (= 0); /* cmp->glyph_len can't be zero; see Bug#8512 */
+ int c;
XChar2b char2b;
struct font_metrics *pcm;
ptrdiff_t pos;
- for (glyph_len = cmp->glyph_len; glyph_len > 0; glyph_len--)
- if ((c = COMPOSITION_GLYPH (cmp, glyph_len - 1)) != '\t')
- break;
+ eassume (0 < glyph_len); /* See Bug#8512. */
+ do
+ c = COMPOSITION_GLYPH (cmp, glyph_len - 1);
+ while (c == '\t' && 0 < --glyph_len);
+
bool right_padded = glyph_len < cmp->glyph_len;
for (i = 0; i < glyph_len; i++)
{
- if ((c = COMPOSITION_GLYPH (cmp, i)) != '\t')
+ c = COMPOSITION_GLYPH (cmp, i);
+ if (c != '\t')
break;
cmp->offsets[i * 2] = cmp->offsets[i * 2 + 1] = 0;
}
produce_image_glyph (it);
else if (it->what == IT_STRETCH)
produce_stretch_glyph (it);
+ else if (it->what == IT_XWIDGET)
+ produce_xwidget_glyph (it);
done:
/* Accumulate dimensions. Note: can't assume that it->descent > 0
/* Use normal cursor if not blinked off. */
if (!w->cursor_off_p)
{
+ if (glyph != NULL && glyph->type == XWIDGET_GLYPH)
+ return NO_CURSOR;
if (glyph != NULL && glyph->type == IMAGE_GLYPH)
{
if (cursor_type == FILLED_BOX_CURSOR)
/* Using a block cursor on large images can be very annoying.
So use a hollow cursor for "large" images.
If image is not transparent (no mask), also use hollow cursor. */
- struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id);
+ struct image *img = IMAGE_OPT_FROM_ID (f, glyph->u.img_id);
if (img != NULL && IMAGEP (img->spec))
{
/* Arbitrarily, interpret "Large" as >32x32 and >NxN
}
}
-#ifdef HAVE_WINDOW_SYSTEM
/* When we've written over the cursor, arrange for it to
be displayed again. */
if (FRAME_WINDOW_P (f)
&& phys_cursor_on_p && !w->phys_cursor_on_p)
{
+#ifdef HAVE_WINDOW_SYSTEM
int hpos = w->phys_cursor.hpos;
/* When the window is hscrolled, cursor hpos can legitimately be
display_and_set_cursor (w, true, hpos, w->phys_cursor.vpos,
w->phys_cursor.x, w->phys_cursor.y);
unblock_input ();
- }
#endif /* HAVE_WINDOW_SYSTEM */
+ }
}
#ifdef HAVE_WINDOW_SYSTEM
clip_to_bounds (INT_MIN, XINT (x), INT_MAX),
clip_to_bounds (INT_MIN, XINT (y), INT_MAX));
}
+#endif /* HAVE_WINDOW_SYSTEM */
/* Display frame CURSOR, optionally using shape defined by POINTER. */
static void
define_frame_cursor1 (struct frame *f, Cursor cursor, Lisp_Object pointer)
{
+#ifdef HAVE_WINDOW_SYSTEM
+ if (!FRAME_WINDOW_P (f))
+ return;
+
/* Do not change cursor shape while dragging mouse. */
if (EQ (do_mouse_tracking, Qdragging))
return;
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
+# ifdef HAVE_X_WINDOWS
else if (EQ (pointer, intern ("vdrag")))
cursor = FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
-#endif
+# endif
else if (EQ (pointer, intern ("hourglass")))
cursor = FRAME_X_OUTPUT (f)->hourglass_cursor;
else if (EQ (pointer, Qmodeline))
if (cursor != No_Cursor)
FRAME_RIF (f)->define_frame_cursor (f, cursor);
+#endif
}
-#endif /* HAVE_WINDOW_SYSTEM */
-
/* Take proper action when mouse has moved to the mode or header line
or marginal area AREA of window W, x-position X and y-position Y.
X is relative to the start of the text display area of W, so the
int dx, dy, width, height;
ptrdiff_t charpos;
Lisp_Object string, object = Qnil;
- Lisp_Object pos IF_LINT (= Qnil), help;
-
+ Lisp_Object pos UNINIT;
Lisp_Object mouse_face;
int original_x_pixel = x;
struct glyph * glyph = NULL, * row_start_glyph = NULL;
- struct glyph_row *row IF_LINT (= 0);
+ struct glyph_row *row UNINIT;
if (area == ON_MODE_LINE || area == ON_HEADER_LINE)
{
&object, &dx, &dy, &width, &height);
}
- help = Qnil;
+ Lisp_Object help = Qnil;
#ifdef HAVE_WINDOW_SYSTEM
if (IMAGEP (object))
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);
-#endif
+ define_frame_cursor1 (f, cursor, pointer);
}
/* Look for :pointer property on image. */
if (glyph != NULL && glyph->type == IMAGE_GLYPH)
{
- struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id);
+ struct image *img = IMAGE_OPT_FROM_ID (f, glyph->u.img_id);
if (img != NULL && IMAGEP (img->spec))
{
Lisp_Object image_map, hotspot;
{
if (clear_mouse_face (hlinfo))
cursor = No_Cursor;
-#ifdef HAVE_WINDOW_SYSTEM
if (FRAME_WINDOW_P (f) && NILP (pointer))
{
+#ifdef HAVE_WINDOW_SYSTEM
if (area != TEXT_AREA)
cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
else
pointer = Vvoid_text_area_pointer;
- }
#endif
+ }
goto set_cursor;
}
{
/* The mouse-highlighting, if any, comes from an overlay
or text property in the buffer. */
- Lisp_Object buffer IF_LINT (= Qnil);
- Lisp_Object disp_string IF_LINT (= Qnil);
+ Lisp_Object buffer UNINIT;
+ Lisp_Object disp_string UNINIT;
if (STRINGP (object))
{
}
set_cursor:
-
-#ifdef HAVE_WINDOW_SYSTEM
- if (FRAME_WINDOW_P (f))
- define_frame_cursor1 (f, cursor, pointer);
-#else
- /* This is here to prevent a compiler error, about "label at end of
- compound statement". */
- return;
-#endif
+ define_frame_cursor1 (f, cursor, pointer);
}
/* Non-nil means don't actually do any redisplay. */
DEFSYM (Qinhibit_redisplay, "inhibit-redisplay");
- DEFSYM (Qredisplay_internal, "redisplay_internal (C function)");
+ DEFSYM (Qredisplay_internal_xC_functionx, "redisplay_internal (C function)");
DEFVAR_BOOL("inhibit-message", inhibit_message,
doc: /* Non-nil means calls to `message' are not displayed.
/* Name and number of the face used to highlight escape glyphs. */
DEFSYM (Qescape_glyph, "escape-glyph");
- /* Name and number of the face used to highlight non-breaking spaces. */
+ /* Name and number of the face used to highlight non-breaking
+ spaces/hyphens. */
DEFSYM (Qnobreak_space, "nobreak-space");
+ DEFSYM (Qnobreak_hyphen, "nobreak-hyphen");
/* The symbol 'image' which is the car of the lists used to represent
images in Lisp. Also a tool bar style. */
doc: /* Control highlighting of non-ASCII space and hyphen chars.
If the value is t, Emacs highlights non-ASCII chars which have the
same appearance as an ASCII space or hyphen, using the `nobreak-space'
-or `escape-glyph' face respectively.
+or `nobreak-hyphen' face respectively.
U+00A0 (no-break space), U+00AD (soft hyphen), U+2010 (hyphen), and
U+2011 (non-breaking hyphen) are affected.
Vtruncate_partial_width_windows,
doc: /* Non-nil means truncate lines in windows narrower than the frame.
For an integer value, truncate lines in each window narrower than the
-full frame width, provided the window width is less than that integer;
-otherwise, respect the value of `truncate-lines'.
+full frame width, provided the total window width in column units is less
+than that integer; otherwise, respect the value of `truncate-lines'.
+The total width of the window is as returned by `window-total-width', it
+includes the fringes, the continuation and truncation glyphs, the
+display margins (if any), and the scroll bar
For any other non-nil value, truncate lines in all windows that do
not span the full frame width.
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
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,
the buffer when it becomes large. */);
Vmessage_log_max = make_number (1000);
- DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_functions,
- doc: /* Functions called before redisplay, if window sizes have changed.
-The value should be a list of functions that take one argument.
-Just before redisplay, for each frame, if any of its windows have changed
-size since the last redisplay, or have been split or deleted,
-all the functions in the list are called, with the frame as argument. */);
- Vwindow_size_change_functions = Qnil;
-
DEFVAR_LISP ("window-scroll-functions", Vwindow_scroll_functions,
doc: /* List of functions to call before redisplaying a window with scrolling.
Each function is called with two arguments, the window and its new
A value of `grow-only', the default, means let mini-windows grow only;
they return to their normal size when the minibuffer is closed, or the
echo area becomes empty. */);
- Vresize_mini_windows = Qgrow_only;
+ /* Contrary to the doc string, we initialize this to nil, so that
+ loading loadup.el won't try to resize windows before loading
+ window.el, where some functions we need to call for this live.
+ We assign the 'grow-only' value right after loading window.el
+ during loadup. */
+ Vresize_mini_windows = Qnil;
DEFVAR_LISP ("blink-cursor-alist", Vblink_cursor_alist,
doc: /* Alist specifying how to blink the cursor off.
Vredisplay__mode_lines_cause = Fmake_hash_table (0, NULL);
DEFVAR_LISP ("redisplay--variables", Vredisplay__variables,
- doc: /* A list of variables changes to which trigger a thorough redisplay. */);
+ doc: /* A hash-table of variables changing which triggers a thorough redisplay. */);
Vredisplay__variables = Qnil;
+
+ DEFVAR_BOOL ("redisplay--inhibit-bidi", redisplay__inhibit_bidi,
+ doc: /* Non-nil means it is not safe to attempt bidi reordering for display. */);
+ /* Initialize to t, since we need to disable reordering until
+ loadup.el successfully loads charprop.el. */
+ redisplay__inhibit_bidi = true;
}