}
if (part != ON_MODE_LINE && part != ON_HEADER_LINE)
- gx += window_box_left_offset (w, area);
+ {
+ gx += window_box_left_offset (w, area);
+ /* Don't expand over the modeline to make sure the vertical
+ drag cursor is shown early enough. */
+ height = min (height,
+ max (0, WINDOW_BOX_HEIGHT_NO_MODE_LINE (w) - gy));
+ }
}
else
{
gx = (x / width) * width;
y -= gy;
gy += (y / height) * height;
+ if (part != ON_MODE_LINE && part != ON_HEADER_LINE)
+ /* See comment above. */
+ height = min (height,
+ max (0, WINDOW_BOX_HEIGHT_NO_MODE_LINE (w) - gy));
}
break;
gx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
? window_box_right_offset (w, RIGHT_MARGIN_AREA)
: window_box_right_offset (w, TEXT_AREA));
- width = WINDOW_RIGHT_FRINGE_WIDTH (w);
+ if (WINDOW_RIGHT_DIVIDER_WIDTH (w) == 0
+ && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
+ && !WINDOW_RIGHTMOST_P (w))
+ if (gx < WINDOW_PIXEL_WIDTH (w) - width)
+ /* Make sure the vertical border can get her own glyph to the
+ right of the one we build here. */
+ width = WINDOW_RIGHT_FRINGE_WIDTH (w) - width;
+ else
+ width = WINDOW_PIXEL_WIDTH (w) - gx;
+ else
+ width = WINDOW_RIGHT_FRINGE_WIDTH (w);
+
+ goto row_glyph;
+
+ case ON_VERTICAL_BORDER:
+ gx = WINDOW_PIXEL_WIDTH (w) - width;
goto row_glyph;
case ON_SCROLL_BAR:
}
break;
+ case ON_RIGHT_DIVIDER:
+ gx = WINDOW_PIXEL_WIDTH (w) - WINDOW_RIGHT_DIVIDER_WIDTH (w);
+ width = WINDOW_RIGHT_DIVIDER_WIDTH (w);
+ gy = 0;
+ /* The bottom divider prevails. */
+ height = WINDOW_PIXEL_HEIGHT (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w);
+ goto add_edge;;
+
+ case ON_BOTTOM_DIVIDER:
+ gx = 0;
+ width = WINDOW_PIXEL_WIDTH (w);
+ gy = WINDOW_PIXEL_HEIGHT (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w);
+ height = WINDOW_BOTTOM_DIVIDER_WIDTH (w);
+ goto add_edge;
+
default:
;
virtual_glyph:
goto store_rect;
}
+ add_edge:
gx += WINDOW_LEFT_EDGE_X (w);
gy += WINDOW_TOP_EDGE_Y (w);
For strings from wrap-prefix and line-prefix properties,
use the default face, possibly remapped via
Vface_remapping_alist. */
+ /* Note that the fact that we use the face at _buffer_
+ position means that a 'display' property on an overlay
+ string will not inherit the face of that overlay string,
+ but will instead revert to the face of buffer text
+ covered by the overlay. This is visible, e.g., when the
+ overlay specifies a box face, but neither the buffer nor
+ the display string do. This sounds like a design bug,
+ but Emacs always did that since v21.1, so changing that
+ might be a big deal. */
base_face_id = it->string_from_prefix_prop_p
? (!NILP (Vface_remapping_alist)
? lookup_basic_face (it->f, DEFAULT_FACE_ID)
it->object = it->w->contents;
break;
case GET_FROM_STRING:
- it->object = it->string;
+ {
+ struct face *face = FACE_FROM_ID (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
+ displaying. */
+ if (face)
+ it->face_box_p = face->box != FACE_NO_BOX;
+ it->object = it->string;
+ }
break;
case GET_FROM_DISPLAY_VECTOR:
if (it->s)
If this is the last string character displayed, check
the next buffer location. */
else if ((IT_STRING_CHARPOS (*it) >= SCHARS (it->string) - 1)
- && (it->current.overlay_string_index
- == it->n_overlay_strings - 1))
+ /* n_overlay_strings is unreliable unless
+ overlay_string_index is non-negative. */
+ && ((it->current.overlay_string_index >= 0
+ && (it->current.overlay_string_index
+ == it->n_overlay_strings - 1))
+ /* A string from display property. */
+ || it->from_disp_prop_p))
{
ptrdiff_t ignore;
int next_face_id;
struct text_pos pos = it->current.pos;
- INC_TEXT_POS (pos, it->multibyte_p);
- next_face_id = face_at_buffer_position
- (it->w, CHARPOS (pos), &ignore,
- (IT_CHARPOS (*it) + TEXT_PROP_DISTANCE_LIMIT), 0,
- -1);
- it->end_of_box_run_p
- = (FACE_FROM_ID (it->f, next_face_id)->box
- == FACE_NO_BOX);
+ /* 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. */
+ if (it->from_disp_prop_p)
+ pos = (it->stack + it->sp - 1)->position;
+ else
+ INC_TEXT_POS (pos, it->multibyte_p);
+
+ 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, 0, -1);
+ it->end_of_box_run_p
+ = (FACE_FROM_ID (it->f, next_face_id)->box
+ == FACE_NO_BOX);
+ }
}
}
}
doesn't fit on the line, e.g. a wide image. */
it->hpos == 0
|| (new_x == it->last_visible_x
- && FRAME_WINDOW_P (it->f)))
+ && FRAME_WINDOW_P (it->f)
+ /* When word-wrap is ON and we have a valid
+ wrap point, we don't allow the last glyph
+ to "just barely fit" on the line. */
+ && (it->line_wrap != WORD_WRAP
+ || wrap_it.sp < 0)))
{
++it->hpos;
it->current_x = new_x;
defaults to the maximum accessible position of the buffer. If TO is t,
use the maximum accessible position that is not a newline character.
-The optional argument X_LIMIT, if non-nil, specifies the maximum text
-width that can be returned. X_LIMIT nil or omitted, means to use the
+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.
+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
+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
+Y-LIMIT are ignored. Since calculating the text height of a large
buffer can take some time, it makes sense to specify this argument if
the size of the buffer is unknown.
-Optional argument MODE_AND_HEADER_LINE nil or omitted means do not
+Optional argument MODE-AND-HEADER-LINE nil or omitted means do not
include the height of the mode- or header-line of WINDOW in the return
value. If it is either the symbol `mode-line' or `header-line', include
only the height of that line, if present, in the return value. If t,
move_it_by_lines (&it, -1);
target_x = it.last_visible_x - !FRAME_WINDOW_P (it.f);
target_is_eol_p = true;
+ /* Under word-wrap, we don't know the x coordinate of
+ the last character displayed on the previous line,
+ which immediately precedes the wrap point. To find
+ out its x coordinate, we try moving to the right
+ margin of the window, which will stop at the wrap
+ point, and then reset target_x to point at the
+ character that precedes the wrap point. This is not
+ needed on GUI frames, because (see below) there we
+ move from the left margin one grapheme cluster at a
+ time, and stop when we hit the wrap point. */
+ if (!FRAME_WINDOW_P (it.f) && it.line_wrap == WORD_WRAP)
+ {
+ void *it_data = NULL;
+ struct it it2;
+
+ SAVE_IT (it2, it, it_data);
+ move_it_in_display_line_to (&it, ZV, target_x,
+ MOVE_TO_POS | MOVE_TO_X);
+ /* If we arrived at target_x, that _is_ the last
+ character on the previous line. */
+ if (it.current_x != target_x)
+ target_x = it.current_x - 1;
+ RESTORE_IT (&it, &it2, it_data);
+ }
}
}
else
new_pos = it.current.pos;
while (it.current_x + it.pixel_width <= target_x
- && rc == MOVE_X_REACHED)
+ && (rc == MOVE_X_REACHED
+ /* Under word-wrap, move_it_in_display_line_to
+ stops at correct coordinates, but sometimes
+ returns MOVE_POS_MATCH_OR_ZV. */
+ || (it.line_wrap == WORD_WRAP
+ && rc == MOVE_POS_MATCH_OR_ZV)))
{
int new_x = it.current_x + it.pixel_width;
if (/* If window is in the process of being destroyed, don't bother
to do anything. */
w->current_matrix != NULL
- /* Don't update mouse highlight if hidden */
+ /* Don't update mouse highlight if hidden. */
&& (draw != DRAW_MOUSE_FACE || !hlinfo->mouse_face_hidden)
/* Recognize when we are called to operate on rows that don't exist
anymore. This can happen when a window is split. */
/* Change the mouse pointer according to what is under it. */
if (FRAME_WINDOW_P (f))
{
+ bool draggable = (! WINDOW_BOTTOMMOST_P (w)
+ || minibuf_level
+ || NILP (Vresize_mini_windows));
+
dpyinfo = FRAME_DISPLAY_INFO (f);
if (STRINGP (string))
{
map = Fget_text_property (pos, Qlocal_map, string);
if (!KEYMAPP (map))
map = Fget_text_property (pos, Qkeymap, string);
- if (!KEYMAPP (map))
+ if (!KEYMAPP (map) && draggable)
cursor = dpyinfo->vertical_scroll_bar_cursor;
}
}
- else
+ else if (draggable)
/* Default mode-line pointer. */
cursor = FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
}
help_echo_string = build_string ("drag-mouse-1: resize");
}
else if (part == ON_BOTTOM_DIVIDER)
- {
- cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor;
- help_echo_string = build_string ("drag-mouse-1: resize");
- }
+ if (! WINDOW_BOTTOMMOST_P (w)
+ || minibuf_level
+ || NILP (Vresize_mini_windows))
+ {
+ cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor;
+ help_echo_string = build_string ("drag-mouse-1: resize");
+ }
+ else
+ cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE
|| part == ON_SCROLL_BAR)
cursor = FRAME_X_OUTPUT (f)->nontext_cursor;