X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/99f10a5dae1270696e9d65f0089985e8c89c28ab..d29d249207dbb944ea93275ea8b8ea07f59c1e82:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index 430551b2b6..54a8c8beb8 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1262,12 +1262,23 @@ Value is the height in pixels of the line at point. */) struct it it; struct text_pos pt; struct window *w = XWINDOW (selected_window); + struct buffer *old_buffer = NULL; + Lisp_Object result; + if (XBUFFER (w->contents) != current_buffer) + { + old_buffer = current_buffer; + set_buffer_internal_1 (XBUFFER (w->contents)); + } SET_TEXT_POS (pt, PT, PT_BYTE); start_display (&it, w, pt); it.vpos = it.current_y = 0; last_height = 0; - return make_number (line_bottom_y (&it)); + result = make_number (line_bottom_y (&it)); + if (old_buffer) + set_buffer_internal_1 (old_buffer); + + return result; } /* Return the default pixel height of text lines in window W. The @@ -2419,7 +2430,13 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) } 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 { @@ -2427,6 +2444,10 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) 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; @@ -2441,7 +2462,22 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) 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: @@ -2472,6 +2508,21 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) } 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: @@ -2492,6 +2543,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) goto store_rect; } + add_edge: gx += WINDOW_LEFT_EDGE_X (w); gy += WINDOW_TOP_EDGE_Y (w); @@ -2539,8 +2591,8 @@ safe_eval_handler (Lisp_Object arg, ptrdiff_t nargs, Lisp_Object *args) following. Return the result, or nil if something went wrong. Prevent redisplay during the evaluation. */ -Lisp_Object -safe_call (ptrdiff_t nargs, Lisp_Object func, ...) +static Lisp_Object +safe__call (bool inhibit_quit, ptrdiff_t nargs, Lisp_Object func, va_list ap) { Lisp_Object val; @@ -2548,21 +2600,20 @@ safe_call (ptrdiff_t nargs, Lisp_Object func, ...) val = Qnil; else { - va_list ap; ptrdiff_t i; ptrdiff_t count = SPECPDL_INDEX (); struct gcpro gcpro1; Lisp_Object *args = alloca (nargs * word_size); args[0] = func; - va_start (ap, func); for (i = 1; i < nargs; i++) args[i] = va_arg (ap, Lisp_Object); - va_end (ap); GCPRO1 (args[0]); gcpro1.nvars = nargs; specbind (Qinhibit_redisplay, Qt); + if (inhibit_quit) + specbind (Qinhibit_quit, Qt); /* Use Qt to ensure debugger does not run, so there is no possibility of wanting to redisplay. */ val = internal_condition_case_n (Ffuncall, nargs, args, Qt, @@ -2574,6 +2625,17 @@ safe_call (ptrdiff_t nargs, Lisp_Object func, ...) return val; } +Lisp_Object +safe_call (ptrdiff_t nargs, Lisp_Object func, ...) +{ + Lisp_Object retval; + va_list ap; + + va_start (ap, func); + retval = safe__call (false, nargs, func, ap); + va_end (ap); + return retval; +} /* Call function FN with one argument ARG. Return the result, or nil if something went wrong. */ @@ -2584,12 +2646,30 @@ safe_call1 (Lisp_Object fn, Lisp_Object arg) return safe_call (2, fn, arg); } +static Lisp_Object +safe__call1 (bool inhibit_quit, Lisp_Object fn, ...) +{ + Lisp_Object retval; + va_list ap; + + va_start (ap, fn); + retval = safe__call (inhibit_quit, 2, fn, ap); + va_end (ap); + return retval; +} + static Lisp_Object Qeval; Lisp_Object safe_eval (Lisp_Object sexpr) { - return safe_call1 (Qeval, sexpr); + return safe__call1 (false, Qeval, sexpr); +} + +static Lisp_Object +safe__eval (bool inhibit_quit, Lisp_Object sexpr) +{ + return safe__call1 (inhibit_quit, Qeval, sexpr); } /* Call function FN with two arguments ARG1 and ARG2. @@ -2928,7 +3008,7 @@ init_iterator (struct it *it, struct window *w, /* 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); - if (face->box != FACE_NO_BOX) + if (face && face->box != FACE_NO_BOX) it->start_of_box_run_p = true; } @@ -3913,6 +3993,15 @@ handle_face_prop (struct it *it) 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) @@ -5946,7 +6035,16 @@ pop_it (struct it *it) 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) @@ -7033,21 +7131,44 @@ get_next_display_element (struct it *it) 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); + } } } } @@ -8313,7 +8434,7 @@ move_it_in_display_line_to (struct it *it, void *ppos_data = NULL; int may_wrap = 0; enum it_method prev_method = it->method; - ptrdiff_t prev_pos = IT_CHARPOS (*it); + ptrdiff_t closest_pos IF_LINT (= 0), prev_pos = IT_CHARPOS (*it); int saw_smaller_pos = prev_pos < to_charpos; /* Don't produce glyphs in produce_glyphs. */ @@ -8330,16 +8451,21 @@ move_it_in_display_line_to (struct it *it, atx_it.sp = -1; /* Use ppos_it under bidi reordering to save a copy of IT for the - position > CHARPOS that is the closest to CHARPOS. We restore - that position in IT when we have scanned the entire display line - without finding a match for CHARPOS and all the character - positions are greater than CHARPOS. */ + initial position. We restore that position in IT when we have + scanned the entire display line without finding a match for + TO_CHARPOS and all the character positions are greater than + TO_CHARPOS. We then restart the scan from the initial position, + and stop at CLOSEST_POS, which is a position > TO_CHARPOS that is + the closest to TO_CHARPOS. */ if (it->bidi_p) { - SAVE_IT (ppos_it, *it, ppos_data); - SET_TEXT_POS (ppos_it.current.pos, ZV, ZV_BYTE); if ((op & MOVE_TO_POS) && IT_CHARPOS (*it) >= to_charpos) - SAVE_IT (ppos_it, *it, ppos_data); + { + SAVE_IT (ppos_it, *it, ppos_data); + closest_pos = IT_CHARPOS (*it); + } + else + closest_pos = ZV; } #define BUFFER_POS_REACHED_P() \ @@ -8430,7 +8556,7 @@ move_it_in_display_line_to (struct it *it, } else { - if (it->line_wrap == WORD_WRAP) + if (it->line_wrap == WORD_WRAP && it->area == TEXT_AREA) { if (IT_DISPLAYING_WHITESPACE (it)) may_wrap = 1; @@ -8483,8 +8609,8 @@ move_it_in_display_line_to (struct it *it, if (it->bidi_p && (op & MOVE_TO_POS) && IT_CHARPOS (*it) > to_charpos - && IT_CHARPOS (*it) < IT_CHARPOS (ppos_it)) - SAVE_IT (ppos_it, *it, ppos_data); + && IT_CHARPOS (*it) < closest_pos) + closest_pos = IT_CHARPOS (*it); continue; } @@ -8564,7 +8690,12 @@ move_it_in_display_line_to (struct it *it, 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; @@ -8706,9 +8837,14 @@ move_it_in_display_line_to (struct it *it, { if (!saw_smaller_pos && IT_CHARPOS (*it) > to_charpos) { - if (IT_CHARPOS (ppos_it) < ZV) + if (closest_pos < ZV) { RESTORE_IT (it, &ppos_it, ppos_data); + /* Don't recurse if closest_pos is equal to + to_charpos, since we have just tried that. */ + if (closest_pos != to_charpos) + move_it_in_display_line_to (it, closest_pos, -1, + MOVE_TO_POS); result = MOVE_POS_MATCH_OR_ZV; } else @@ -8738,8 +8874,8 @@ move_it_in_display_line_to (struct it *it, if (it->bidi_p && (op & MOVE_TO_POS) && IT_CHARPOS (*it) >= to_charpos - && IT_CHARPOS (*it) < IT_CHARPOS (ppos_it)) - SAVE_IT (ppos_it, *it, ppos_data); + && IT_CHARPOS (*it) < closest_pos) + closest_pos = IT_CHARPOS (*it); /* Stop if lines are truncated and IT's current x-position is past the right edge of the window now. */ @@ -8765,8 +8901,14 @@ move_it_in_display_line_to (struct it *it, && IT_CHARPOS (*it) > to_charpos)) { if (it->bidi_p - && !at_eob_p && IT_CHARPOS (ppos_it) < ZV) - RESTORE_IT (it, &ppos_it, ppos_data); + && !BUFFER_POS_REACHED_P () + && !at_eob_p && closest_pos < ZV) + { + RESTORE_IT (it, &ppos_it, ppos_data); + if (closest_pos != to_charpos) + move_it_in_display_line_to (it, closest_pos, -1, + MOVE_TO_POS); + } result = MOVE_POS_MATCH_OR_ZV; break; } @@ -8780,8 +8922,13 @@ move_it_in_display_line_to (struct it *it, && !saw_smaller_pos && IT_CHARPOS (*it) > to_charpos) { - if (IT_CHARPOS (ppos_it) < ZV) - RESTORE_IT (it, &ppos_it, ppos_data); + if (closest_pos < ZV) + { + RESTORE_IT (it, &ppos_it, ppos_data); + if (closest_pos != to_charpos) + move_it_in_display_line_to (it, closest_pos, -1, + MOVE_TO_POS); + } result = MOVE_POS_MATCH_OR_ZV; break; } @@ -9409,6 +9556,7 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos) ptrdiff_t start_charpos, i; int nchars_per_row = (it->last_visible_x - it->first_visible_x) / FRAME_COLUMN_WIDTH (it->f); + bool hit_pos_limit = false; ptrdiff_t pos_limit; /* Start at the beginning of the screen line containing IT's @@ -9425,8 +9573,11 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos) pos_limit = BEGV; else pos_limit = max (start_charpos + dvpos * nchars_per_row, BEGV); + for (i = -dvpos; i > 0 && IT_CHARPOS (*it) > pos_limit; --i) back_to_previous_visible_line_start (it); + if (i > 0 && IT_CHARPOS (*it) <= pos_limit) + hit_pos_limit = true; reseat (it, it->current.pos, 1); /* Move further back if we end up in a string or an image. */ @@ -9470,6 +9621,25 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos) else bidi_unshelve_cache (it2data, 1); } + else if (hit_pos_limit && pos_limit > BEGV + && dvpos < 0 && it2.vpos < -dvpos) + { + /* If we hit the limit, but still didn't make it far enough + back, that means there's a display string with a newline + covering a large chunk of text, and that caused + back_to_previous_visible_line_start try to go too far. + Punish those who commit such atrocities by going back + until we've reached DVPOS, after lifting the limit, which + could make it slow for very long lines. "If it hurts, + don't do that!" */ + dvpos += it2.vpos; + RESTORE_IT (it, it, it2data); + for (i = -dvpos; i > 0; --i) + { + back_to_previous_visible_line_start (it); + it->vpos--; + } + } else RESTORE_IT (it, it, it2data); } @@ -9498,19 +9668,23 @@ character. TO, if non-nil, specifies the last text position and defaults to the maximum accessible position of the buffer. If TO is t, use the maximum accessible position that is not a newline character. -The optional argument X_LIMIT, if non-nil, specifies the maximum text -width that can be returned. X_LIMIT nil or omitted, means to use the +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, @@ -10027,19 +10201,17 @@ message_with_string (const char *m, Lisp_Object string, int log) { if (m) { - /* ENCODE_SYSTEM below can GC and/or relocate the Lisp - String whose data pointer might be passed to us in M. So - we use a local copy. */ - char *fmt = xstrdup (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 = 0; - fprintf (stderr, fmt, SDATA (ENCODE_SYSTEM (string))); + fprintf (stderr, m, SDATA (ENCODE_SYSTEM (string))); if (!cursor_in_echo_area) fprintf (stderr, "\n"); fflush (stderr); - xfree (fmt); } } else if (INTERACTIVE) @@ -11403,7 +11575,7 @@ prepare_menu_bars (void) } } } - safe_call1 (Vpre_redisplay_function, windows); + safe__call1 (true, Vpre_redisplay_function, windows); } /* Update all frame titles based on their buffer names, etc. We do @@ -11634,11 +11806,6 @@ update_menu_bar (struct frame *f, int save_match_data, int hooks_run) #ifdef HAVE_WINDOW_SYSTEM -/* Tool-bar item index of the item on which a mouse button was pressed - or -1. */ - -int last_tool_bar_item; - /* Select `frame' temporarily without running all the code in do_switch_frame. FIXME: Maybe do_switch_frame should be trimmed down similarly @@ -12440,7 +12607,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p, where the button was pressed, disregarding where it was released. */ if (NILP (Vmouse_highlight) && !down_p) - prop_idx = last_tool_bar_item; + prop_idx = f->last_tool_bar_item; /* If item is disabled, do nothing. */ enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P); @@ -12452,7 +12619,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p, /* Show item in pressed state. */ if (!NILP (Vmouse_highlight)) show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN); - last_tool_bar_item = prop_idx; + f->last_tool_bar_item = prop_idx; } else { @@ -12477,7 +12644,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p, event.arg = key; event.modifiers = modifiers; kbd_buffer_store_event (&event); - last_tool_bar_item = -1; + f->last_tool_bar_item = -1; } } @@ -12527,8 +12694,7 @@ note_tool_bar_highlight (struct frame *f, int x, int y) mouse_down_p = (x_mouse_grabbed (dpyinfo) && f == dpyinfo->last_mouse_frame); - if (mouse_down_p - && last_tool_bar_item != prop_idx) + if (mouse_down_p && f->last_tool_bar_item != prop_idx) return; draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED; @@ -14247,7 +14413,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, pos_after, 0); if (prop_pos >= pos_before) - bpos_max = prop_pos - 1; + bpos_max = prop_pos; } if (INTEGERP (chprop)) { @@ -14321,7 +14487,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, pos_after, 0); if (prop_pos >= pos_before) - bpos_max = prop_pos - 1; + bpos_max = prop_pos; } if (INTEGERP (chprop)) { @@ -14351,7 +14517,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, GLYPH_BEFORE and GLYPH_AFTER. */ if (!((row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end) && BUFFERP (glyph->object) && glyph->charpos == pt_old) - && !(bpos_max < pt_old && pt_old <= bpos_covered)) + && !(bpos_max <= pt_old && pt_old <= bpos_covered)) { /* An empty line has a single glyph whose OBJECT is zero and whose CHARPOS is the position of a newline on that line. @@ -15470,29 +15636,32 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste /* As soon as we've found the exact match for point, or the first suitable row whose ends_at_zv_p flag is set, we are done. */ - at_zv_p = - MATRIX_ROW (w->current_matrix, w->cursor.vpos)->ends_at_zv_p; - if (rv && !at_zv_p - && w->cursor.hpos >= 0 - && w->cursor.hpos < MATRIX_ROW_USED (w->current_matrix, - w->cursor.vpos)) - { - struct glyph_row *candidate = - MATRIX_ROW (w->current_matrix, w->cursor.vpos); - struct glyph *g = - candidate->glyphs[TEXT_AREA] + w->cursor.hpos; - ptrdiff_t endpos = MATRIX_ROW_END_CHARPOS (candidate); - - exact_match_p = - (BUFFERP (g->object) && g->charpos == PT) - || (INTEGERP (g->object) - && (g->charpos == PT - || (g->charpos == 0 && endpos - 1 == PT))); - } - if (rv && (at_zv_p || exact_match_p)) + if (rv) { - rc = CURSOR_MOVEMENT_SUCCESS; - break; + at_zv_p = MATRIX_ROW (w->current_matrix, + w->cursor.vpos)->ends_at_zv_p; + if (!at_zv_p + && w->cursor.hpos >= 0 + && w->cursor.hpos < MATRIX_ROW_USED (w->current_matrix, + w->cursor.vpos)) + { + struct glyph_row *candidate = + MATRIX_ROW (w->current_matrix, w->cursor.vpos); + struct glyph *g = + candidate->glyphs[TEXT_AREA] + w->cursor.hpos; + ptrdiff_t endpos = MATRIX_ROW_END_CHARPOS (candidate); + + exact_match_p = + (BUFFERP (g->object) && g->charpos == PT) + || (INTEGERP (g->object) + && (g->charpos == PT + || (g->charpos == 0 && endpos - 1 == PT))); + } + if (at_zv_p || exact_match_p) + { + rc = CURSOR_MOVEMENT_SUCCESS; + break; + } } if (MATRIX_ROW_BOTTOM_Y (row) == last_y) break; @@ -15535,9 +15704,6 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste return rc; } -#if !defined USE_TOOLKIT_SCROLL_BARS || defined USE_GTK -static -#endif void set_vertical_scroll_bar (struct window *w) { @@ -16291,12 +16457,50 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) /* Consider the following case: Window starts at BEGV, there is invisible, intangible text at BEGV, so that display starts at some point START > BEGV. It can happen that we are called with - PT somewhere between BEGV and START. Try to handle that case. */ + PT somewhere between BEGV and START. Try to handle that case, + and similar ones. */ if (w->cursor.vpos < 0) { - struct glyph_row *row = w->current_matrix->rows; - if (row->mode_line_p) - ++row; + /* First, try locating the proper glyph row for PT. */ + struct glyph_row *row = + row_containing_pos (w, PT, w->current_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, + row_containing_pos fails to find the row, because no glyphs + with appropriate buffer positions are present in the row. + Therefore, we next try to find the row which shows the 1st + position after the invisible text. */ + if (!row) + { + Lisp_Object val = + get_char_property_and_overlay (make_number (PT), Qinvisible, + Qnil, NULL); + + if (TEXT_PROP_MEANS_INVISIBLE (val)) + { + ptrdiff_t alt_pos; + Lisp_Object invis_end = + Fnext_single_char_property_change (make_number (PT), Qinvisible, + Qnil, Qnil); + + if (NATNUMP (invis_end)) + alt_pos = XFASTINT (invis_end); + else + alt_pos = ZV; + row = row_containing_pos (w, alt_pos, w->current_matrix->rows, + NULL, 0); + } + } + /* Finally, fall back on the first row of the window after the + header line (if any). This is slightly better than not + displaying the cursor at all. */ + if (!row) + { + row = w->current_matrix->rows; + if (row->mode_line_p) + ++row; + } set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); } @@ -18507,6 +18711,7 @@ insert_left_trunc_glyphs (struct it *it) truncate_it.current_x = 0; truncate_it.face_id = DEFAULT_FACE_ID; truncate_it.glyph_row = &scratch_glyph_row; + truncate_it.area = TEXT_AREA; truncate_it.glyph_row->used[TEXT_AREA] = 0; CHARPOS (truncate_it.position) = BYTEPOS (truncate_it.position) = -1; truncate_it.object = make_number (0); @@ -20119,7 +20324,12 @@ display_line (struct it *it) /* If we truncate lines, we are done when the last displayed glyphs reach past the right margin of the window. */ if (it->line_wrap == TRUNCATE - && (FRAME_WINDOW_P (it->f) && WINDOW_RIGHT_FRINGE_WIDTH (it->w) + && ((FRAME_WINDOW_P (it->f) + /* Images are preprocessed in produce_image_glyph such + that they are cropped at the right edge of the + window, so an image glyph will always end exactly at + last_visible_x, even if there's no right fringe. */ + && (WINDOW_RIGHT_FRINGE_WIDTH (it->w) || it->what == IT_IMAGE)) ? (it->current_x >= it->last_visible_x) : (it->current_x > it->last_visible_x))) { @@ -20152,19 +20362,26 @@ display_line (struct it *it) i = row->used[TEXT_AREA] - (i + 1); } - it->current_x = x_before; - if (!FRAME_WINDOW_P (it->f)) + /* produce_special_glyphs overwrites the last glyph, so + we don't want that if we want to keep that last + glyph, which means it's an image. */ + if (it->current_x > it->last_visible_x) { - for (n = row->used[TEXT_AREA]; i < n; ++i) + it->current_x = x_before; + if (!FRAME_WINDOW_P (it->f)) + { + for (n = row->used[TEXT_AREA]; i < n; ++i) + { + row->used[TEXT_AREA] = i; + produce_special_glyphs (it, IT_TRUNCATION); + } + } + else { row->used[TEXT_AREA] = i; produce_special_glyphs (it, IT_TRUNCATION); } - } - else - { - row->used[TEXT_AREA] = i; - produce_special_glyphs (it, IT_TRUNCATION); + it->hpos = hpos_before; } } else if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) @@ -20183,13 +20400,13 @@ display_line (struct it *it) goto at_end_of_line; } it->current_x = x_before; + it->hpos = hpos_before; } row->truncated_on_right_p = 1; it->continuation_lines_width = 0; reseat_at_next_visible_line_start (it, 0); row->ends_at_zv_p = FETCH_BYTE (IT_BYTEPOS (*it) - 1) != '\n'; - it->hpos = hpos_before; break; } } @@ -20203,9 +20420,12 @@ display_line (struct it *it) && IT_CHARPOS (*it) != CHARPOS (row->start.pos)) { if (!FRAME_WINDOW_P (it->f) - || (row->reversed_p - ? WINDOW_RIGHT_FRINGE_WIDTH (it->w) - : WINDOW_LEFT_FRINGE_WIDTH (it->w)) == 0) + || (((row->reversed_p + ? WINDOW_RIGHT_FRINGE_WIDTH (it->w) + : WINDOW_LEFT_FRINGE_WIDTH (it->w)) == 0) + /* Don't let insert_left_trunc_glyphs overwrite the + first glyph of the row if it is an image. */ + && row->glyphs[TEXT_AREA]->type != IMAGE_GLYPH)) insert_left_trunc_glyphs (it); row->truncated_on_left_p = 1; } @@ -20742,6 +20962,30 @@ Value is the new character position of point. */) 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 @@ -20780,7 +21024,12 @@ Value is the new character position of point. */) 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; @@ -21631,7 +21880,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, if (CONSP (XCDR (elt))) { Lisp_Object spec; - spec = safe_eval (XCAR (XCDR (elt))); + spec = safe__eval (true, XCAR (XCDR (elt))); n += display_mode_element (it, depth, field_width - n, precision - n, spec, props, risky); @@ -22448,7 +22697,7 @@ decode_mode_spec (struct window *w, register int c, int field_width, return decode_mode_spec_buf; no_value: { - char* p = decode_mode_spec_buf; + char *p = decode_mode_spec_buf; int pad = width - 2; while (pad-- > 0) *p++ = ' '; @@ -23196,7 +23445,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w)); } - prop = buffer_local_value_1 (prop, it->w->contents); + prop = buffer_local_value (prop, it->w->contents); if (EQ (prop, Qunbound)) prop = Qnil; } @@ -23248,7 +23497,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, return OK_PIXELS (pixels); } - car = buffer_local_value_1 (car, it->w->contents); + car = buffer_local_value (car, it->w->contents); if (EQ (car, Qunbound)) car = Qnil; } @@ -23425,7 +23674,7 @@ get_char_face_and_encoding (struct frame *f, int c, int face_id, #endif { eassert (face != NULL); - PREPARE_FACE_FOR_DISPLAY (f, face); + prepare_face_for_display (f, face); } return face; @@ -23448,7 +23697,7 @@ get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph, /* Make sure X resources of the face are allocated. */ eassert (face != NULL); - PREPARE_FACE_FOR_DISPLAY (f, face); + prepare_face_for_display (f, face); if (two_byte_p) *two_byte_p = 0; @@ -23765,7 +24014,7 @@ fill_stretch_glyph_string (struct glyph_string *s, int start, int end) s->ybase += voffset; /* The case that face->gc == 0 is handled when drawing the glyph - string by calling PREPARE_FACE_FOR_DISPLAY. */ + string by calling prepare_face_for_display. */ eassert (s->face); return glyph - s->row->glyphs[s->area]; } @@ -24363,13 +24612,16 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, else overlap_hl = DRAW_NORMAL_TEXT; + if (hl != overlap_hl) + clip_head = head; j = i; BUILD_GLYPH_STRINGS (j, start, h, t, overlap_hl, dummy_x, last_x); start = i; compute_overhangs_and_x (t, head->x, 1); prepend_glyph_string_lists (&head, &tail, h, t); - clip_head = head; + if (clip_head == NULL) + clip_head = head; } /* Prepend glyph strings for glyphs in front of the first glyph @@ -24390,7 +24642,8 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, else overlap_hl = DRAW_NORMAL_TEXT; - clip_head = head; + if (hl == overlap_hl || clip_head == NULL) + clip_head = head; BUILD_GLYPH_STRINGS (i, start, h, t, overlap_hl, dummy_x, last_x); for (s = h; s; s = s->next) @@ -24414,13 +24667,16 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, else overlap_hl = DRAW_NORMAL_TEXT; + if (hl != overlap_hl) + clip_tail = tail; BUILD_GLYPH_STRINGS (end, i, h, t, overlap_hl, x, last_x); /* Because BUILD_GLYPH_STRINGS updates the first argument, we don't have `end = i;' here. */ compute_overhangs_and_x (h, tail->x + tail->width, 0); append_glyph_string_lists (&head, &tail, h, t); - clip_tail = tail; + if (clip_tail == NULL) + clip_tail = tail; } /* Append glyph strings for glyphs following the last glyph @@ -24438,7 +24694,8 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, else overlap_hl = DRAW_NORMAL_TEXT; - clip_tail = tail; + if (hl == overlap_hl || clip_tail == NULL) + clip_tail = tail; i++; /* We must include the Ith glyph. */ BUILD_GLYPH_STRINGS (end, i, h, t, overlap_hl, x, last_x); @@ -24706,7 +24963,7 @@ produce_image_glyph (struct it *it) 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); + prepare_face_for_display (it->f, face); if (it->image_id < 0) { @@ -24984,7 +25241,7 @@ produce_stretch_glyph (struct it *it) { struct face *face = FACE_FROM_ID (it->f, it->face_id); font = face->font ? face->font : FRAME_FONT (it->f); - PREPARE_FACE_FOR_DISPLAY (it->f, face); + prepare_face_for_display (it->f, face); } #endif @@ -25448,7 +25705,7 @@ produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym) face = FACE_FROM_ID (it->f, face_id); font = face->font ? face->font : FRAME_FONT (it->f); - PREPARE_FACE_FOR_DISPLAY (it->f, face); + prepare_face_for_display (it->f, face); if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM) { @@ -26789,9 +27046,6 @@ draw_phys_cursor_glyph (struct window *w, struct glyph_row *row, /* Erase the image of a cursor of window W from the screen. */ -#ifndef HAVE_NTGUI -static -#endif void erase_phys_cursor (struct window *w) { @@ -27100,7 +27354,7 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw) 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. */ @@ -28317,8 +28571,8 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, else if (area == ON_MODE_LINE) { Lisp_Object default_help - = buffer_local_value_1 (Qmode_line_default_help_echo, - w->contents); + = buffer_local_value (Qmode_line_default_help_echo, + w->contents); if (STRINGP (default_help)) { @@ -28334,6 +28588,10 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, /* 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)) { @@ -28350,11 +28608,11 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, 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; } @@ -28598,10 +28856,15 @@ note_mouse_highlight (struct frame *f, int x, int y) 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; @@ -30138,8 +30401,8 @@ Bind this around calls to `message' to let it take effect. */); DEFVAR_LISP ("menu-bar-update-hook", Vmenu_bar_update_hook, doc: /* Normal hook run to update the menu bar definitions. Redisplay runs this hook before it redisplays the menu bar. -This is used to update submenus such as Buffers, -whose contents depend on various data. */); +This is used to update menus such as Buffers, whose contents depend on +various data. */); Vmenu_bar_update_hook = Qnil; DEFVAR_LISP ("menu-updating-frame", Vmenu_updating_frame,