X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/1d71218362bb1c75ed0c630d80b9710637538bcc..6ad9aaa961f1ac376bdaa1a5516d0481e6c7fafa:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index f068290078..3c144f4f5f 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -301,6 +301,7 @@ extern Lisp_Object Qface, Qinvisible, Qwidth; Lisp_Object Vdisplay_pixels_per_inch; Lisp_Object Qspace, QCalign_to, QCrelative_width, QCrelative_height; Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise; +Lisp_Object Qcenter; Lisp_Object Qmargin, Qpointer; extern Lisp_Object Qheight; extern Lisp_Object QCwidth, QCheight, QCascent; @@ -314,7 +315,7 @@ Lisp_Object Vshow_trailing_whitespace; extern Lisp_Object Voverflow_newline_into_fringe; /* Test if overflow newline into fringe. Called with iterator IT - at or past right window margin, and with IT->current_x set. */ + at or past right window margin, and with IT->current_x set. */ #define IT_OVERFLOW_NEWLINE_INTO_FRINGE(it) \ (!NILP (Voverflow_newline_into_fringe) \ @@ -403,6 +404,13 @@ int multiple_frames; Lisp_Object Vglobal_mode_string; + +/* List of variables (symbols) which hold markers for overlay arrows. + The symbols on this list are examined during redisplay to determine + where to display overlay arrows. */ + +Lisp_Object Voverlay_arrow_variable_list; + /* Marker for where to display an arrow on top of the buffer text. */ Lisp_Object Voverlay_arrow_position; @@ -411,11 +419,17 @@ Lisp_Object Voverlay_arrow_position; Lisp_Object Voverlay_arrow_string; -/* Values of those variables at last redisplay. However, if - Voverlay_arrow_position is a marker, last_arrow_position is its +/* Values of those variables at last redisplay are stored as + properties on `overlay-arrow-position' symbol. However, if + Voverlay_arrow_position is a marker, last-arrow-position is its numerical position. */ -static Lisp_Object last_arrow_position, last_arrow_string; +Lisp_Object Qlast_arrow_position, Qlast_arrow_string; + +/* Alternative overlay-arrow-string and overlay-arrow-bitmap + properties on a symbol in overlay-arrow-variable-list. */ + +Lisp_Object Qoverlay_arrow_string, Qoverlay_arrow_bitmap; /* Like mode-line-format, but for the title bar on a visible frame. */ @@ -756,10 +770,6 @@ enum move_it_result #define CLEAR_FACE_CACHE_COUNT 500 static int clear_face_cache_count; -/* Record the previous terminal frame we displayed. */ - -static struct frame *previous_terminal_frame; - /* Non-zero while redisplay_internal is in progress. */ int redisplaying_p; @@ -832,10 +842,11 @@ static struct text_pos display_prop_end P_ ((struct it *, Lisp_Object, static int compute_window_start_on_continuation_line P_ ((struct window *)); static Lisp_Object safe_eval_handler P_ ((Lisp_Object)); static void insert_left_trunc_glyphs P_ ((struct it *)); -static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *)); +static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *, + Lisp_Object)); static void extend_face_to_end_of_line P_ ((struct it *)); static int append_space P_ ((struct it *, int)); -static int make_cursor_line_fully_visible P_ ((struct window *)); +static int make_cursor_line_fully_visible P_ ((struct window *, int)); static int try_scrolling P_ ((Lisp_Object, int, EMACS_INT, EMACS_INT, int, int)); static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *)); static int trailing_whitespace_p P_ ((int)); @@ -1778,8 +1789,9 @@ get_glyph_string_clip_rect (s, nr) height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent); if (height < r.height) { - r.y = s->ybase + glyph->descent - height; - r.height = height; + int max_y = r.y + r.height; + r.y = min (max_y, s->ybase + glyph->descent - height); + r.height = min (max_y - r.y, height); } } @@ -1904,10 +1916,14 @@ check_it (it) xassert (STRINGP (it->string)); xassert (IT_STRING_CHARPOS (*it) >= 0); } - else if (it->method == next_element_from_buffer) + else { - /* Check that character and byte positions agree. */ - xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it))); + xassert (IT_STRING_CHARPOS (*it) < 0); + if (it->method == next_element_from_buffer) + { + /* Check that character and byte positions agree. */ + xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it))); + } } if (it->dpvec) @@ -2020,12 +2036,14 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) it->current.overlay_string_index = -1; it->current.dpvec_index = -1; it->base_face_id = base_face_id; + it->string = Qnil; + IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1; /* The window in which we iterate over current_buffer: */ XSETWINDOW (it->window, w); it->w = w; it->f = XFRAME (w->frame); - + /* Extra space between lines (on window systems only). */ if (base_face_id == DEFAULT_FACE_ID && FRAME_WINDOW_P (it->f)) @@ -2038,9 +2056,9 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) /* If realized faces have been removed, e.g. because of face attribute changes of named faces, recompute them. When running - in batch mode, the face cache of Vterminal_frame is null. If + in batch mode, the face cache of the initial frame is null. If we happen to get called, make a dummy face cache. */ - if (noninteractive && FRAME_FACE_CACHE (it->f) == NULL) + if (FRAME_FACE_CACHE (it->f) == NULL) init_frame_faces (it->f); if (FRAME_FACE_CACHE (it->f)->used == 0) recompute_basic_faces (it->f); @@ -3484,43 +3502,6 @@ handle_single_display_prop (it, prop, object, position, it->voffset = - (XFLOATINT (value) * (FONT_HEIGHT (face->font))); } -#endif /* HAVE_WINDOW_SYSTEM */ - } - else if (CONSP (prop) - && (EQ (XCAR (prop), Qleft_fringe) - || EQ (XCAR (prop), Qright_fringe)) - && CONSP (XCDR (prop))) - { - unsigned face_id = DEFAULT_FACE_ID; - - /* `(left-fringe BITMAP FACE)'. */ - if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f)) - return 0; - -#ifdef HAVE_WINDOW_SYSTEM - value = XCAR (XCDR (prop)); - if (!NUMBERP (value) - || !valid_fringe_bitmap_id_p (XINT (value))) - return 0; - - if (CONSP (XCDR (XCDR (prop)))) - { - Lisp_Object face_name = XCAR (XCDR (XCDR (prop))); - face_id = lookup_named_face (it->f, face_name, 'A'); - if (face_id < 0) - return 0; - } - - if (EQ (XCAR (prop), Qleft_fringe)) - { - it->left_user_fringe_bitmap = XINT (value); - it->left_user_fringe_face_id = face_id; - } - else - { - it->right_user_fringe_bitmap = XINT (value); - it->right_user_fringe_face_id = face_id; - } #endif /* HAVE_WINDOW_SYSTEM */ } else if (!it->string_from_display_prop_p) @@ -3541,6 +3522,64 @@ handle_single_display_prop (it, prop, object, position, text properties change there. */ it->stop_charpos = position->charpos; + if (CONSP (prop) + && (EQ (XCAR (prop), Qleft_fringe) + || EQ (XCAR (prop), Qright_fringe)) + && CONSP (XCDR (prop))) + { + unsigned face_id = DEFAULT_FACE_ID; + + /* Save current settings of IT so that we can restore them + when we are finished with the glyph property value. */ + + /* `(left-fringe BITMAP FACE)'. */ + if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f)) + return 0; + +#ifdef HAVE_WINDOW_SYSTEM + value = XCAR (XCDR (prop)); + if (!NUMBERP (value) + || !valid_fringe_bitmap_id_p (XINT (value))) + return 0; + + if (CONSP (XCDR (XCDR (prop)))) + { + Lisp_Object face_name = XCAR (XCDR (XCDR (prop))); + + face_id = lookup_named_face (it->f, face_name, 'A'); + if (face_id < 0) + return 0; + } + + push_it (it); + + it->area = TEXT_AREA; + it->what = IT_IMAGE; + it->image_id = -1; /* no image */ + it->position = start_pos; + it->object = NILP (object) ? it->w->buffer : object; + it->method = next_element_from_image; + it->face_id = face_id; + + /* Say that we haven't consumed the characters with + `display' property yet. The call to pop_it in + set_iterator_to_next will clean this up. */ + *position = start_pos; + + if (EQ (XCAR (prop), Qleft_fringe)) + { + it->left_user_fringe_bitmap = XINT (value); + it->left_user_fringe_face_id = face_id; + } + else + { + it->right_user_fringe_bitmap = XINT (value); + it->right_user_fringe_face_id = face_id; + } +#endif /* HAVE_WINDOW_SYSTEM */ + return 1; + } + location = Qunbound; if (CONSP (prop) && CONSP (XCAR (prop))) { @@ -3566,16 +3605,11 @@ handle_single_display_prop (it, prop, object, position, value = prop; } + valid_p = (STRINGP (value) #ifdef HAVE_WINDOW_SYSTEM - if (FRAME_TERMCAP_P (it->f)) - valid_p = STRINGP (value); - else - valid_p = (STRINGP (value) - || (CONSP (value) && EQ (XCAR (value), Qspace)) - || valid_image_p (value)); -#else /* not HAVE_WINDOW_SYSTEM */ - valid_p = STRINGP (value); + || (!FRAME_TERMCAP_P (it->f) && valid_image_p (value)) #endif /* not HAVE_WINDOW_SYSTEM */ + || (CONSP (value) && EQ (XCAR (value), Qspace))); if ((EQ (location, Qleft_margin) || EQ (location, Qright_margin) @@ -5557,15 +5591,18 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) saved_glyph_row = it->glyph_row; it->glyph_row = NULL; +#define BUFFER_POS_REACHED_P() \ + ((op & MOVE_TO_POS) != 0 \ + && BUFFERP (it->object) \ + && IT_CHARPOS (*it) >= to_charpos) + while (1) { int x, i, ascent = 0, descent = 0; /* Stop when ZV or TO_CHARPOS reached. */ if (!get_next_display_element (it) - || ((op & MOVE_TO_POS) != 0 - && BUFFERP (it->object) - && IT_CHARPOS (*it) >= to_charpos)) + || BUFFER_POS_REACHED_P ()) { result = MOVE_POS_MATCH_OR_ZV; break; @@ -5652,7 +5689,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) #ifdef HAVE_WINDOW_SYSTEM if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) { - if (!get_next_display_element (it)) + if (!get_next_display_element (it) + || BUFFER_POS_REACHED_P ()) { result = MOVE_POS_MATCH_OR_ZV; break; @@ -5724,7 +5762,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) #ifdef HAVE_WINDOW_SYSTEM if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) { - if (!get_next_display_element (it)) + if (!get_next_display_element (it) + || BUFFER_POS_REACHED_P ()) { result = MOVE_POS_MATCH_OR_ZV; break; @@ -5741,6 +5780,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) } } +#undef BUFFER_POS_REACHED_P + /* Restore the iterator settings altered at the beginning of this function. */ it->glyph_row = saved_glyph_row; @@ -6546,8 +6587,8 @@ message2_nolog (m, nbytes, multibyte) do_pending_window_change (0); echo_area_display (1); do_pending_window_change (0); - if (frame_up_to_date_hook != 0 && ! gc_in_progress) - (*frame_up_to_date_hook) (f); + if (FRAME_DISPLAY (f)->frame_up_to_date_hook != 0 && ! gc_in_progress) + (*FRAME_DISPLAY (f)->frame_up_to_date_hook) (f); } } @@ -6632,8 +6673,8 @@ message3_nolog (m, nbytes, multibyte) do_pending_window_change (0); echo_area_display (1); do_pending_window_change (0); - if (frame_up_to_date_hook != 0 && ! gc_in_progress) - (*frame_up_to_date_hook) (f); + if (FRAME_DISPLAY (f)->frame_up_to_date_hook != 0 && ! gc_in_progress) + (*FRAME_DISPLAY (f)->frame_up_to_date_hook) (f); } } @@ -7656,11 +7697,11 @@ clear_garbaged_frames () { Lisp_Object tail, frame; int changed_count = 0; - + FOR_EACH_FRAME (tail, frame) { struct frame *f = XFRAME (frame); - + if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f)) { if (f->resized_p) @@ -7674,7 +7715,7 @@ clear_garbaged_frames () f->resized_p = 0; } } - + frame_garbaged = 0; if (changed_count) ++windows_or_buffers_changed; @@ -7707,11 +7748,11 @@ echo_area_display (update_frame_p) /* The terminal frame is used as the first Emacs frame on the Mac OS. */ #ifndef MAC_OS8 #ifdef HAVE_WINDOW_SYSTEM - /* When Emacs starts, selected_frame may be a visible terminal - frame, even if we run under a window system. If we let this - through, a message would be displayed on the terminal. */ - if (EQ (selected_frame, Vterminal_frame) - && !NILP (Vwindow_system)) + /* When Emacs starts, selected_frame may be the initial terminal + frame. If we let this through, a message would be displayed on + the terminal. */ + if (FRAME_TERMCAP_P (XFRAME (selected_frame)) + && FRAME_TTY (XFRAME (selected_frame))->type == NULL) return 0; #endif /* HAVE_WINDOW_SYSTEM */ #endif @@ -7762,7 +7803,7 @@ echo_area_display (update_frame_p) Can do with a display update of the echo area, unless we displayed some mode lines. */ update_single_window (w, 1); - rif->flush_display (f); + FRAME_RIF (f)->flush_display (f); } else update_frame (f, 1, 1); @@ -8223,8 +8264,8 @@ x_cursor_to (vpos, hpos, y, x) { BLOCK_INPUT; display_and_set_cursor (w, 1, hpos, vpos, x, y); - if (rif->flush_display_optional) - rif->flush_display_optional (SELECTED_FRAME ()); + if (FRAME_RIF (SELECTED_FRAME ())->flush_display_optional) + FRAME_RIF (SELECTED_FRAME ())->flush_display_optional (SELECTED_FRAME ()); UNBLOCK_INPUT; } } @@ -8323,7 +8364,7 @@ update_tool_bar (f, save_match_data) /* Redisplay the tool-bar if we changed it. */ if (! NILP (Fequal (old_tool_bar, f->tool_bar_items))) w->update_mode_line = Qt; - + UNGCPRO; unbind_to (count, Qnil); @@ -9293,6 +9334,153 @@ redisplay () } +static Lisp_Object +overlay_arrow_string_or_property (var, pbitmap) + Lisp_Object var; + int *pbitmap; +{ + Lisp_Object pstr = Fget (var, Qoverlay_arrow_string); + Lisp_Object bitmap; + + if (pbitmap) + { + *pbitmap = 0; + if (bitmap = Fget (var, Qoverlay_arrow_bitmap), INTEGERP (bitmap)) + *pbitmap = XINT (bitmap); + } + + if (!NILP (pstr)) + return pstr; + return Voverlay_arrow_string; +} + +/* Return 1 if there are any overlay-arrows in current_buffer. */ +static int +overlay_arrow_in_current_buffer_p () +{ + Lisp_Object vlist; + + for (vlist = Voverlay_arrow_variable_list; + CONSP (vlist); + vlist = XCDR (vlist)) + { + Lisp_Object var = XCAR (vlist); + Lisp_Object val; + + if (!SYMBOLP (var)) + continue; + val = find_symbol_value (var); + if (MARKERP (val) + && current_buffer == XMARKER (val)->buffer) + return 1; + } + return 0; +} + + +/* Return 1 if any overlay_arrows have moved or overlay-arrow-string + has changed. */ + +static int +overlay_arrows_changed_p () +{ + Lisp_Object vlist; + + for (vlist = Voverlay_arrow_variable_list; + CONSP (vlist); + vlist = XCDR (vlist)) + { + Lisp_Object var = XCAR (vlist); + Lisp_Object val, pstr; + + if (!SYMBOLP (var)) + continue; + val = find_symbol_value (var); + if (!MARKERP (val)) + continue; + if (! EQ (COERCE_MARKER (val), + Fget (var, Qlast_arrow_position)) + || ! (pstr = overlay_arrow_string_or_property (var, 0), + EQ (pstr, Fget (var, Qlast_arrow_string)))) + return 1; + } + return 0; +} + +/* Mark overlay arrows to be updated on next redisplay. */ + +static void +update_overlay_arrows (up_to_date) + int up_to_date; +{ + Lisp_Object vlist; + + for (vlist = Voverlay_arrow_variable_list; + CONSP (vlist); + vlist = XCDR (vlist)) + { + Lisp_Object var = XCAR (vlist); + + if (!SYMBOLP (var)) + continue; + + if (up_to_date > 0) + { + Lisp_Object val = find_symbol_value (var); + Fput (var, Qlast_arrow_position, + COERCE_MARKER (val)); + Fput (var, Qlast_arrow_string, + overlay_arrow_string_or_property (var, 0)); + } + else if (up_to_date < 0 + || !NILP (Fget (var, Qlast_arrow_position))) + { + Fput (var, Qlast_arrow_position, Qt); + Fput (var, Qlast_arrow_string, Qt); + } + } +} + + +/* Return overlay arrow string at row, or nil. */ + +static Lisp_Object +overlay_arrow_at_row (f, row, pbitmap) + struct frame *f; + struct glyph_row *row; + int *pbitmap; +{ + Lisp_Object vlist; + + for (vlist = Voverlay_arrow_variable_list; + CONSP (vlist); + vlist = XCDR (vlist)) + { + Lisp_Object var = XCAR (vlist); + Lisp_Object val; + + if (!SYMBOLP (var)) + continue; + + val = find_symbol_value (var); + + if (MARKERP (val) + && current_buffer == XMARKER (val)->buffer + && (MATRIX_ROW_START_CHARPOS (row) == marker_position (val))) + { + val = overlay_arrow_string_or_property (var, pbitmap); + if (FRAME_WINDOW_P (f)) + return Qt; + else if (STRINGP (val)) + return val; + break; + } + } + + *pbitmap = 0; + return Qnil; +} + /* Return 1 if point moved out of or into a composition. Otherwise return 0. PREV_BUF and PREV_PT are the last point buffer and position. BUF and PT are the current point buffer and position. */ @@ -9382,7 +9570,7 @@ select_frame_for_redisplay (frame) { Lisp_Object tail, sym, val; Lisp_Object old = selected_frame; - + selected_frame = frame; for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail)) @@ -9498,17 +9686,16 @@ redisplay_internal (preserve_echo_area) if (face_change_count) ++windows_or_buffers_changed; - if (! FRAME_WINDOW_P (sf) - && previous_terminal_frame != sf) + if (FRAME_TERMCAP_P (sf) + && FRAME_TTY (sf)->previous_terminal_frame != sf) { - /* Since frames on an ASCII terminal share the same display - area, displaying a different frame means redisplay the whole - thing. */ + /* Since frames on a single ASCII terminal share the same + display area, displaying a different frame means redisplay + the whole thing. */ windows_or_buffers_changed++; SET_FRAME_GARBAGED (sf); - XSETFRAME (Vterminal_frame, sf); + FRAME_TTY (sf)->previous_terminal_frame = sf; } - previous_terminal_frame = sf; /* Set the visible flags for all frames. Do this before checking for resized or garbaged frames; they want to know if their frames @@ -9530,6 +9717,7 @@ redisplay_internal (preserve_echo_area) } } + /* Notice any pending interrupt request to change frame size. */ do_pending_window_change (1); @@ -9572,8 +9760,7 @@ redisplay_internal (preserve_echo_area) /* If specs for an arrow have changed, do thorough redisplay to ensure we remove any arrow that should no longer exist. */ - if (! EQ (COERCE_MARKER (Voverlay_arrow_position), last_arrow_position) - || ! EQ (Voverlay_arrow_string, last_arrow_string)) + if (overlay_arrows_changed_p ()) consider_all_windows_p = windows_or_buffers_changed = 1; /* Normally the message* functions will have already displayed and @@ -9890,7 +10077,7 @@ redisplay_internal (preserve_echo_area) { struct frame *f = XFRAME (frame); - if (FRAME_WINDOW_P (f) || f == sf) + if (FRAME_WINDOW_P (f) || FRAME_TERMCAP_P (f) || f == sf) { if (! EQ (frame, selected_frame)) /* Select the frame, for the sake of frame-local @@ -9905,16 +10092,16 @@ redisplay_internal (preserve_echo_area) /* Mark all the scroll bars to be removed; we'll redeem the ones we want when we redisplay their windows. */ - if (condemn_scroll_bars_hook) - condemn_scroll_bars_hook (f); + if (FRAME_DISPLAY (f)->condemn_scroll_bars_hook) + FRAME_DISPLAY (f)->condemn_scroll_bars_hook (f); if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f)) redisplay_windows (FRAME_ROOT_WINDOW (f)); /* Any scroll bars which redisplay_windows should have nuked should now go away. */ - if (judge_scroll_bars_hook) - judge_scroll_bars_hook (f); + if (FRAME_DISPLAY (f)->judge_scroll_bars_hook) + FRAME_DISPLAY (f)->judge_scroll_bars_hook (f); /* If fonts changed, display again. */ /* ??? rms: I suspect it is a mistake to jump all the way @@ -9966,8 +10153,8 @@ redisplay_internal (preserve_echo_area) { struct frame *f = updated[i]; mark_window_display_accurate (f->root_window, 1); - if (frame_up_to_date_hook) - frame_up_to_date_hook (f); + if (FRAME_DISPLAY (f)->frame_up_to_date_hook) + FRAME_DISPLAY (f)->frame_up_to_date_hook (f); } } } @@ -10033,11 +10220,7 @@ redisplay_internal (preserve_echo_area) CHARPOS (this_line_start_pos) = 0; /* Let the overlay arrow be updated the next time. */ - if (!NILP (last_arrow_position)) - { - last_arrow_position = Qt; - last_arrow_string = Qt; - } + update_overlay_arrows (0); /* If we pause after scrolling, some rows in the current matrices of some windows are not valid. */ @@ -10053,11 +10236,11 @@ redisplay_internal (preserve_echo_area) consider_all_windows_p is set. */ mark_window_display_accurate_1 (w, 1); - last_arrow_position = COERCE_MARKER (Voverlay_arrow_position); - last_arrow_string = Voverlay_arrow_string; + /* Say overlay arrows are up to date. */ + update_overlay_arrows (1); - if (frame_up_to_date_hook != 0) - frame_up_to_date_hook (sf); + if (FRAME_DISPLAY (sf)->frame_up_to_date_hook != 0) + FRAME_DISPLAY (sf)->frame_up_to_date_hook (sf); } update_mode_lines = 0; @@ -10250,16 +10433,14 @@ mark_window_display_accurate (window, accurate_p) if (accurate_p) { - last_arrow_position = COERCE_MARKER (Voverlay_arrow_position); - last_arrow_string = Voverlay_arrow_string; + update_overlay_arrows (1); } else { /* Force a thorough redisplay the next time by setting last_arrow_position and last_arrow_string to t, which is unequal to any useful value of Voverlay_arrow_... */ - last_arrow_position = Qt; - last_arrow_string = Qt; + update_overlay_arrows (-1); } } @@ -10549,12 +10730,17 @@ run_window_scroll_functions (window, startp) A value of 1 means there is nothing to be done. (Either the line is fully visible, or it cannot be made so, or we cannot tell.) + + If FORCE_P is non-zero, return 0 even if partial visible cursor row + is higher than window. + A value of 0 means the caller should do scrolling as if point had gone off the screen. */ static int -make_cursor_line_fully_visible (w) +make_cursor_line_fully_visible (w, force_p) struct window *w; + int force_p; { struct glyph_matrix *matrix; struct glyph_row *row; @@ -10572,6 +10758,9 @@ make_cursor_line_fully_visible (w) if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (row)) return 1; + if (force_p) + return 0; + /* If the row the cursor is in is taller than the window's height, it's not clear what to do, so do nothing. */ window_height = window_box_height (w); @@ -10668,7 +10857,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, int amount_to_scroll = 0; Lisp_Object aggressive; int height; - int end_scroll_margin; + int extra_scroll_margin_lines = last_line_misfit ? 1 : 0; #if GLYPH_DEBUG debug_method_add (w, "try_scrolling"); @@ -10686,6 +10875,12 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, else this_scroll_margin = 0; + /* Force scroll_conservatively to have a reasonable value so it doesn't + cause an overflow while computing how much to scroll. */ + if (scroll_conservatively) + scroll_conservatively = min (scroll_conservatively, + MOST_POSITIVE_FIXNUM / FRAME_LINE_HEIGHT (f)); + /* Compute how much we should try to scroll maximally to bring point into view. */ if (scroll_step || scroll_conservatively || temp_scroll_step) @@ -10711,11 +10906,13 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, CHARPOS (scroll_margin_pos) = XINT (window_end); BYTEPOS (scroll_margin_pos) = CHAR_TO_BYTE (CHARPOS (scroll_margin_pos)); - end_scroll_margin = this_scroll_margin + !!last_line_misfit; - if (end_scroll_margin) + if (this_scroll_margin || extra_scroll_margin_lines) { start_display (&it, w, scroll_margin_pos); - move_it_vertically (&it, - end_scroll_margin); + if (this_scroll_margin) + move_it_vertically (&it, - this_scroll_margin); + if (extra_scroll_margin_lines) + move_it_by_lines (&it, - extra_scroll_margin_lines, 0); scroll_margin_pos = it.current.pos; } @@ -10850,10 +11047,10 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, /* If cursor ends up on a partially visible line, treat that as being off the bottom of the screen. */ - if (! make_cursor_line_fully_visible (w)) + if (! make_cursor_line_fully_visible (w, extra_scroll_margin_lines <= 1)) { clear_glyph_matrix (w->desired_matrix); - last_line_misfit = 1; + ++extra_scroll_margin_lines; goto too_near_end; } rc = SCROLLING_SUCCESS; @@ -11010,8 +11207,7 @@ try_cursor_movement (window, startp, scroll_step) && INTEGERP (w->window_end_vpos) && XFASTINT (w->window_end_vpos) < w->current_matrix->nrows && (FRAME_WINDOW_P (f) - || !MARKERP (Voverlay_arrow_position) - || current_buffer != XMARKER (Voverlay_arrow_position)->buffer)) + || !overlay_arrow_in_current_buffer_p ())) { int this_scroll_margin; struct glyph_row *row = NULL; @@ -11143,7 +11339,7 @@ try_cursor_movement (window, startp, scroll_step) else { set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); - if (!make_cursor_line_fully_visible (w)) + if (!make_cursor_line_fully_visible (w, 0)) rc = CURSOR_MOVEMENT_MUST_SCROLL; else rc = CURSOR_MOVEMENT_SUCCESS; @@ -11173,7 +11369,7 @@ set_vertical_scroll_bar (w) which reflect the whole buffer size, with special markers indicating narrowing, and scrollbars which reflect only the visible region. - + Note that mini-buffers sometimes aren't displaying any text. */ if (!MINI_WINDOW_P (w) || (w == XWINDOW (minibuf_window) @@ -11185,7 +11381,7 @@ set_vertical_scroll_bar (w) /* I don't think this is guaranteed to be right. For the moment, we'll pretend it is. */ end = BUF_Z (buf) - XFASTINT (w->window_end_pos) - BUF_BEGV (buf); - + if (end < start) end = start; if (whole < (end - start)) @@ -11195,7 +11391,9 @@ set_vertical_scroll_bar (w) start = end = whole = 0; /* Indicate what this scroll bar ought to be displaying now. */ - set_vertical_scroll_bar_hook (w, end - start, whole, start); + if (FRAME_DISPLAY (XFRAME (w->frame))->set_vertical_scroll_bar_hook) + (*FRAME_DISPLAY (XFRAME (w->frame))->set_vertical_scroll_bar_hook) + (w, end - start, whole, start); } @@ -11474,7 +11672,7 @@ redisplay_window (window, just_this_one_p) new_vpos = window_box_height (w) / 2; } - if (!make_cursor_line_fully_visible (w)) + if (!make_cursor_line_fully_visible (w, 0)) { /* Point does appear, but on a line partly visible at end of window. Move it back to a fully-visible line. */ @@ -11611,7 +11809,7 @@ redisplay_window (window, just_this_one_p) /* Forget any recorded base line for line number display. */ w->base_line_number = Qnil; - if (!make_cursor_line_fully_visible (w)) + if (!make_cursor_line_fully_visible (w, 1)) { clear_glyph_matrix (w->desired_matrix); last_line_misfit = 1; @@ -11771,7 +11969,7 @@ redisplay_window (window, just_this_one_p) set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); } - if (!make_cursor_line_fully_visible (w)) + if (!make_cursor_line_fully_visible (w, centering_position > 0)) { /* If vscroll is enabled, disable it and try again. */ if (w->vscroll) @@ -11784,6 +11982,7 @@ redisplay_window (window, just_this_one_p) /* If centering point failed to make the whole line visible, put point at the top instead. That has to make the whole line visible, if it can be done. */ + clear_glyph_matrix (w->desired_matrix); centering_position = 0; goto point_at_top; } @@ -11915,7 +12114,8 @@ redisplay_window (window, just_this_one_p) /* Note that we actually used the scroll bar attached to this window, so it shouldn't be deleted at the end of redisplay. */ - redeem_scroll_bar_hook (w); + if (FRAME_DISPLAY (f)->redeem_scroll_bar_hook) + (*FRAME_DISPLAY (f)->redeem_scroll_bar_hook) (w); } /* Restore current_buffer and value of point in it. */ @@ -12124,10 +12324,10 @@ try_window_reusing_current_matrix (w) if (run.height > 0 && run.current_y != run.desired_y) { update_begin (f); - rif->update_window_begin_hook (w); - rif->clear_window_mouse_face (w); - rif->scroll_run_hook (w, &run); - rif->update_window_end_hook (w, 0, 0); + FRAME_RIF (f)->update_window_begin_hook (w); + FRAME_RIF (f)->clear_window_mouse_face (w); + FRAME_RIF (f)->scroll_run_hook (w, &run); + FRAME_RIF (f)->update_window_end_hook (w, 0, 0); update_end (f); } @@ -12297,10 +12497,10 @@ try_window_reusing_current_matrix (w) if (run.height) { update_begin (f); - rif->update_window_begin_hook (w); - rif->clear_window_mouse_face (w); - rif->scroll_run_hook (w, &run); - rif->update_window_end_hook (w, 0, 0); + FRAME_RIF (f)->update_window_begin_hook (w); + FRAME_RIF (f)->clear_window_mouse_face (w); + FRAME_RIF (f)->scroll_run_hook (w, &run); + FRAME_RIF (f)->update_window_end_hook (w, 0, 0); update_end (f); } @@ -12725,7 +12925,7 @@ try_window_id (w) /* Window must either use window-based redisplay or be full width. */ if (!FRAME_WINDOW_P (f) - && (!line_ins_del_ok + && (!FRAME_LINE_INS_DEL_OK (f) || !WINDOW_FULL_WIDTH_P (w))) GIVE_UP (4); @@ -12760,8 +12960,7 @@ try_window_id (w) GIVE_UP (10); /* Can use this if overlay arrow position and or string have changed. */ - if (!EQ (last_arrow_position, COERCE_MARKER (Voverlay_arrow_position)) - || !EQ (last_arrow_string, Voverlay_arrow_string)) + if (overlay_arrows_changed_p ()) GIVE_UP (12); @@ -13133,10 +13332,10 @@ try_window_id (w) if (FRAME_WINDOW_P (f)) { - rif->update_window_begin_hook (w); - rif->clear_window_mouse_face (w); - rif->scroll_run_hook (w, &run); - rif->update_window_end_hook (w, 0, 0); + FRAME_RIF (f)->update_window_begin_hook (w); + FRAME_RIF (f)->clear_window_mouse_face (w); + FRAME_RIF (f)->scroll_run_hook (w, &run); + FRAME_RIF (f)->update_window_end_hook (w, 0, 0); } else { @@ -13154,36 +13353,36 @@ try_window_id (w) { /* Scroll last_unchanged_at_beg_row to the end of the window down dvpos lines. */ - set_terminal_window (end); + set_terminal_window (f, end); /* On dumb terminals delete dvpos lines at the end before inserting dvpos empty lines. */ - if (!scroll_region_ok) - ins_del_lines (end - dvpos, -dvpos); + if (!FRAME_SCROLL_REGION_OK (f)) + ins_del_lines (f, end - dvpos, -dvpos); /* Insert dvpos empty lines in front of last_unchanged_at_beg_row. */ - ins_del_lines (from, dvpos); + ins_del_lines (f, from, dvpos); } else if (dvpos < 0) { /* Scroll up last_unchanged_at_beg_vpos to the end of the window to last_unchanged_at_beg_vpos - |dvpos|. */ - set_terminal_window (end); + set_terminal_window (f, end); /* Delete dvpos lines in front of last_unchanged_at_beg_vpos. ins_del_lines will set the cursor to the given vpos and emit |dvpos| delete line sequences. */ - ins_del_lines (from + dvpos, dvpos); + ins_del_lines (f, from + dvpos, dvpos); /* On a dumb terminal insert dvpos empty lines at the end. */ - if (!scroll_region_ok) - ins_del_lines (end + dvpos, -dvpos); + if (!FRAME_SCROLL_REGION_OK (f)) + ins_del_lines (f, end + dvpos, -dvpos); } - set_terminal_window (0); + set_terminal_window (f, 0); } update_end (f); @@ -13698,14 +13897,15 @@ usage: (trace-to-stderr STRING &rest OBJECTS) */) arrow. Only used for non-window-redisplay windows. */ static struct glyph_row * -get_overlay_arrow_glyph_row (w) +get_overlay_arrow_glyph_row (w, overlay_arrow_string) struct window *w; + Lisp_Object overlay_arrow_string; { struct frame *f = XFRAME (WINDOW_FRAME (w)); struct buffer *buffer = XBUFFER (w->buffer); struct buffer *old = current_buffer; - const unsigned char *arrow_string = SDATA (Voverlay_arrow_string); - int arrow_len = SCHARS (Voverlay_arrow_string); + const unsigned char *arrow_string = SDATA (overlay_arrow_string); + int arrow_len = SCHARS (overlay_arrow_string); const unsigned char *arrow_end = arrow_string + arrow_len; const unsigned char *p; struct it it; @@ -13732,7 +13932,7 @@ get_overlay_arrow_glyph_row (w) /* Get its face. */ ilisp = make_number (p - arrow_string); - face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string); + face = Fget_text_property (ilisp, Qface, overlay_arrow_string); it.face_id = compute_char_face (f, it.c, face); /* Compute its width, get its glyphs. */ @@ -14171,6 +14371,8 @@ display_line (it) struct it *it; { struct glyph_row *row = it->glyph_row; + int overlay_arrow_bitmap; + Lisp_Object overlay_arrow_string; /* We always start displaying at hpos zero even if hscrolled. */ xassert (it->hpos == 0 && it->current_x == 0); @@ -14566,17 +14768,16 @@ display_line (it) mark this glyph row as the one containing the overlay arrow. This is clearly a mess with variable size fonts. It would be better to let it be displayed like cursors under X. */ - if (MARKERP (Voverlay_arrow_position) - && current_buffer == XMARKER (Voverlay_arrow_position)->buffer - && (MATRIX_ROW_START_CHARPOS (row) - == marker_position (Voverlay_arrow_position)) - && STRINGP (Voverlay_arrow_string) - && ! overlay_arrow_seen) + if (! overlay_arrow_seen + && (overlay_arrow_string + = overlay_arrow_at_row (it->f, row, &overlay_arrow_bitmap), + !NILP (overlay_arrow_string))) { /* Overlay arrow in window redisplay is a fringe bitmap. */ if (!FRAME_WINDOW_P (it->f)) { - struct glyph_row *arrow_row = get_overlay_arrow_glyph_row (it->w); + struct glyph_row *arrow_row + = get_overlay_arrow_glyph_row (it->w, overlay_arrow_string); struct glyph *glyph = arrow_row->glyphs[TEXT_AREA]; struct glyph *arrow_end = glyph + arrow_row->used[TEXT_AREA]; struct glyph *p = row->glyphs[TEXT_AREA]; @@ -14600,6 +14801,7 @@ display_line (it) } overlay_arrow_seen = 1; + it->w->overlay_arrow_bitmap = overlay_arrow_bitmap; row->overlay_arrow_p = 1; } @@ -14883,6 +15085,8 @@ display_mode_line (w, face_id, format) init_iterator (&it, w, -1, -1, NULL, face_id); prepare_desired_row (it.glyph_row); + it.glyph_row->mode_line_p = 1; + if (! mode_line_inverse_video) /* Force the mode-line to be displayed in the default face. */ it.base_face_id = it.face_id = DEFAULT_FACE_ID; @@ -14899,7 +15103,6 @@ display_mode_line (w, face_id, format) compute_line_metrics (&it); it.glyph_row->full_width_p = 1; - it.glyph_row->mode_line_p = 1; it.glyph_row->continued_p = 0; it.glyph_row->truncated_on_left_p = 0; it.glyph_row->truncated_on_right_p = 0; @@ -16513,6 +16716,252 @@ invisible_p (propval, list) return 0; } +/* Calculate a width or height in pixels from a specification using + the following elements: + + SPEC ::= + NUM - a (fractional) multiple of the default font width/height + (NUM) - specifies exactly NUM pixels + UNIT - a fixed number of pixels, see below. + ELEMENT - size of a display element in pixels, see below. + (NUM . SPEC) - equals NUM * SPEC + (+ SPEC SPEC ...) - add pixel values + (- SPEC SPEC ...) - subtract pixel values + (- SPEC) - negate pixel value + + NUM ::= + INT or FLOAT - a number constant + SYMBOL - use symbol's (buffer local) variable binding. + + UNIT ::= + in - pixels per inch *) + mm - pixels per 1/1000 meter *) + cm - pixels per 1/100 meter *) + width - width of current font in pixels. + height - height of current font in pixels. + + *) using the ratio(s) defined in display-pixels-per-inch. + + ELEMENT ::= + + left-fringe - left fringe width in pixels + right-fringe - right fringe width in pixels + + left-margin - left margin width in pixels + right-margin - right margin width in pixels + + scroll-bar - scroll-bar area width in pixels + + Examples: + + Pixels corresponding to 5 inches: + (5 . in) + + Total width of non-text areas on left side of window (if scroll-bar is on left): + '(space :width (+ left-fringe left-margin scroll-bar)) + + Align to first text column (in header line): + '(space :align-to 0) + + Align to middle of text area minus half the width of variable `my-image' + containing a loaded image: + '(space :align-to (0.5 . (- text my-image))) + + Width of left margin minus width of 1 character in the default font: + '(space :width (- left-margin 1)) + + Width of left margin minus width of 2 characters in the current font: + '(space :width (- left-margin (2 . width))) + + Center 1 character over left-margin (in header line): + '(space :align-to (+ left-margin (0.5 . left-margin) -0.5)) + + Different ways to express width of left fringe plus left margin minus one pixel: + '(space :width (- (+ left-fringe left-margin) (1))) + '(space :width (+ left-fringe left-margin (- (1)))) + '(space :width (+ left-fringe left-margin (-1))) + +*/ + +#define NUMVAL(X) \ + ((INTEGERP (X) || FLOATP (X)) \ + ? XFLOATINT (X) \ + : - 1) + +int +calc_pixel_width_or_height (res, it, prop, font, width_p, align_to) + double *res; + struct it *it; + Lisp_Object prop; + void *font; + int width_p, *align_to; +{ + double pixels; + +#define OK_PIXELS(val) ((*res = (double)(val)), 1) +#define OK_ALIGN_TO(val) ((*align_to = (int)(val)), 1) + + if (NILP (prop)) + return OK_PIXELS (0); + + if (SYMBOLP (prop)) + { + if (SCHARS (SYMBOL_NAME (prop)) == 2) + { + char *unit = SDATA (SYMBOL_NAME (prop)); + + if (unit[0] == 'i' && unit[1] == 'n') + pixels = 1.0; + else if (unit[0] == 'm' && unit[1] == 'm') + pixels = 25.4; + else if (unit[0] == 'c' && unit[1] == 'm') + pixels = 2.54; + else + pixels = 0; + if (pixels > 0) + { + double ppi; + if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0) + || (CONSP (Vdisplay_pixels_per_inch) + && (ppi = (width_p + ? NUMVAL (XCAR (Vdisplay_pixels_per_inch)) + : NUMVAL (XCDR (Vdisplay_pixels_per_inch))), + ppi > 0))) + return OK_PIXELS (ppi / pixels); + + return 0; + } + } + +#ifdef HAVE_WINDOW_SYSTEM + if (EQ (prop, Qheight)) + return OK_PIXELS (font ? FONT_HEIGHT ((XFontStruct *)font) : FRAME_LINE_HEIGHT (it->f)); + if (EQ (prop, Qwidth)) + return OK_PIXELS (font ? FONT_WIDTH ((XFontStruct *)font) : FRAME_COLUMN_WIDTH (it->f)); +#else + if (EQ (prop, Qheight) || EQ (prop, Qwidth)) + return OK_PIXELS (1); +#endif + + if (EQ (prop, Qtext)) + return OK_PIXELS (width_p + ? window_box_width (it->w, TEXT_AREA) + : WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w)); + + if (align_to && *align_to < 0) + { + *res = 0; + if (EQ (prop, Qleft)) + return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA)); + if (EQ (prop, Qright)) + return OK_ALIGN_TO (window_box_right_offset (it->w, TEXT_AREA)); + if (EQ (prop, Qcenter)) + return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA) + + window_box_width (it->w, TEXT_AREA) / 2); + if (EQ (prop, Qleft_fringe)) + return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) + ? WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (it->w) + : window_box_right_offset (it->w, LEFT_MARGIN_AREA)); + if (EQ (prop, Qright_fringe)) + return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) + ? window_box_right_offset (it->w, RIGHT_MARGIN_AREA) + : window_box_right_offset (it->w, TEXT_AREA)); + if (EQ (prop, Qleft_margin)) + return OK_ALIGN_TO (window_box_left_offset (it->w, LEFT_MARGIN_AREA)); + if (EQ (prop, Qright_margin)) + return OK_ALIGN_TO (window_box_left_offset (it->w, RIGHT_MARGIN_AREA)); + if (EQ (prop, Qscroll_bar)) + return OK_ALIGN_TO (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w) + ? 0 + : (window_box_right_offset (it->w, RIGHT_MARGIN_AREA) + + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) + ? WINDOW_RIGHT_FRINGE_WIDTH (it->w) + : 0))); + } + else + { + if (EQ (prop, Qleft_fringe)) + return OK_PIXELS (WINDOW_LEFT_FRINGE_WIDTH (it->w)); + if (EQ (prop, Qright_fringe)) + return OK_PIXELS (WINDOW_RIGHT_FRINGE_WIDTH (it->w)); + if (EQ (prop, Qleft_margin)) + return OK_PIXELS (WINDOW_LEFT_MARGIN_WIDTH (it->w)); + if (EQ (prop, Qright_margin)) + return OK_PIXELS (WINDOW_RIGHT_MARGIN_WIDTH (it->w)); + if (EQ (prop, Qscroll_bar)) + return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w)); + } + + prop = Fbuffer_local_value (prop, it->w->buffer); + } + + if (INTEGERP (prop) || FLOATP (prop)) + { + int base_unit = (width_p + ? FRAME_COLUMN_WIDTH (it->f) + : FRAME_LINE_HEIGHT (it->f)); + return OK_PIXELS (XFLOATINT (prop) * base_unit); + } + + if (CONSP (prop)) + { + Lisp_Object car = XCAR (prop); + Lisp_Object cdr = XCDR (prop); + + if (SYMBOLP (car)) + { +#ifdef HAVE_WINDOW_SYSTEM + if (valid_image_p (prop)) + { + int id = lookup_image (it->f, prop); + struct image *img = IMAGE_FROM_ID (it->f, id); + + return OK_PIXELS (width_p ? img->width : img->height); + } +#endif + if (EQ (car, Qplus) || EQ (car, Qminus)) + { + int first = 1; + double px; + + pixels = 0; + while (CONSP (cdr)) + { + if (!calc_pixel_width_or_height (&px, it, XCAR (cdr), + font, width_p, align_to)) + return 0; + if (first) + pixels = (EQ (car, Qplus) ? px : -px), first = 0; + else + pixels += px; + cdr = XCDR (cdr); + } + if (EQ (car, Qminus)) + pixels = -pixels; + return OK_PIXELS (pixels); + } + + car = Fbuffer_local_value (car, it->w->buffer); + } + + if (INTEGERP (car) || FLOATP (car)) + { + double fact; + pixels = XFLOATINT (car); + if (NILP (cdr)) + return OK_PIXELS (pixels); + if (calc_pixel_width_or_height (&fact, it, cdr, + font, width_p, align_to)) + return OK_PIXELS (pixels * fact); + return 0; + } + + return 0; + } + + return 0; +} + /*********************************************************************** Glyph Display @@ -16703,7 +17152,7 @@ get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p) = FONT_INFO_FROM_ID (f, face->font_info_id); if (font_info) glyph->font_type - = rif->encode_char (glyph->u.ch, char2b, font_info, two_byte_p); + = FRAME_RIF (f)->encode_char (glyph->u.ch, char2b, font_info, two_byte_p); } } @@ -16933,7 +17382,7 @@ x_get_glyph_overhangs (glyph, f, left, right) font = face->font; font_info = FONT_INFO_FROM_ID (f, face->font_info_id); if (font /* ++KFS: Should this be font_info ? */ - && (pcm = rif->per_char_metric (font, &char2b, glyph->font_type))) + && (pcm = FRAME_RIF (f)->per_char_metric (font, &char2b, glyph->font_type))) { if (pcm->rbearing > pcm->width) *right = pcm->rbearing - pcm->width; @@ -17101,7 +17550,7 @@ get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p) struct font_info *font_info = FONT_INFO_FROM_ID (f, face->font_info_id); if (font_info) - rif->encode_char (c, char2b, font_info, 0); + FRAME_RIF (f)->encode_char (c, char2b, font_info, 0); } } @@ -17168,8 +17617,8 @@ compute_overhangs_and_x (s, x, backward_p) { while (s) { - if (rif->compute_glyph_string_overhangs) - rif->compute_glyph_string_overhangs (s); + if (FRAME_RIF (s->f)->compute_glyph_string_overhangs) + FRAME_RIF (s->f)->compute_glyph_string_overhangs (s); x -= s->width; s->x = x; s = s->prev; @@ -17179,8 +17628,8 @@ compute_overhangs_and_x (s, x, backward_p) { while (s) { - if (rif->compute_glyph_string_overhangs) - rif->compute_glyph_string_overhangs (s); + if (FRAME_RIF (s->f)->compute_glyph_string_overhangs) + FRAME_RIF (s->f)->compute_glyph_string_overhangs (s); s->x = x; x += s->width; s = s->next; @@ -17461,9 +17910,9 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p) struct glyph_string *h, *t; /* Compute overhangs for all glyph strings. */ - if (rif->compute_glyph_string_overhangs) + if (FRAME_RIF (f)->compute_glyph_string_overhangs) for (s = head; s; s = s->next) - rif->compute_glyph_string_overhangs (s); + FRAME_RIF (f)->compute_glyph_string_overhangs (s); /* Prepend glyph strings for glyphs in front of the first glyph string that are overwritten because of the first glyph @@ -17531,7 +17980,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p) /* Draw all strings. */ for (s = head; s; s = s->next) - rif->draw_glyph_string (s); + FRAME_RIF (f)->draw_glyph_string (s); if (area == TEXT_AREA && !row->full_width_p @@ -17674,17 +18123,34 @@ produce_image_glyph (it) xassert (it->what == IT_IMAGE); face = FACE_FROM_ID (it->f, it->face_id); + xassert (face); + /* Make sure X resources of the face is loaded. */ + PREPARE_FACE_FOR_DISPLAY (it->f, face); + + if (it->image_id < 0) + { + /* Fringe bitmap. */ + it->ascent = it->phys_ascent = 0; + it->descent = it->phys_descent = 0; + it->pixel_width = 0; + it->nglyphs = 0; + return; + } + img = IMAGE_FROM_ID (it->f, it->image_id); xassert (img); - - /* Make sure X resources of the face and image are loaded. */ - PREPARE_FACE_FOR_DISPLAY (it->f, face); + /* Make sure X resources of the image is loaded. */ prepare_image_for_display (it->f, img); it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face); it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent; it->pixel_width = img->width + 2 * img->hmargin; + /* 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; + /* If this glyph is alone on the last line, adjust it.ascent to minimum row ascent. */ face_ascent = face->font ? FONT_BASE (face->font) : FRAME_BASELINE_OFFSET (it->f); if (face_ascent > it->ascent) @@ -17779,209 +18245,6 @@ append_stretch_glyph (it, object, width, height, ascent) } -/* Calculate a width or height in pixels from a specification using - the following elements: - - SPEC ::= - NUM - a (fractional) multiple of the default font width/height - (NUM) - specifies exactly NUM pixels - UNIT - a fixed number of pixels, see below. - ELEMENT - size of a display element in pixels, see below. - (NUM . SPEC) - equals NUM * SPEC - (+ SPEC SPEC ...) - add pixel values - (- SPEC SPEC ...) - subtract pixel values - (- SPEC) - negate pixel value - - NUM ::= - INT or FLOAT - a number constant - SYMBOL - use symbol's (buffer local) variable binding. - - UNIT ::= - in - pixels per inch *) - mm - pixels per 1/1000 meter *) - cm - pixels per 1/100 meter *) - width - width of current font in pixels. - height - height of current font in pixels. - - *) using the ratio(s) defined in display-pixels-per-inch. - - ELEMENT ::= - - left-fringe - left fringe width in pixels - (left-fringe . nil) - left fringe width if inside margins, else 0 - (left-fringe . t) - left fringe width if outside margins, else 0 - - right-fringe - right fringe width in pixels - (right-fringe . nil) - right fringe width if inside margins, else 0 - (right-fringe . t) - right fringe width if outside margins, else 0 - - left-margin - left margin width in pixels - right-margin - right margin width in pixels - - scroll-bar - scroll-bar area width in pixels - (scroll-bar . left) - scroll-bar width if on left, else 0 - (scroll-bar . right) - scroll-bar width if on right, else 0 - - Examples: - - Pixels corresponding to 5 inches: - (5 . in) - - Total width of non-text areas on left side of window: - (+ left-fringe left-margin (scroll-bar . left)) - - Total width of fringes if inside display margins: - (+ (left-fringe) (right-fringe)) - - Width of left margin minus width of 1 character in the default font: - (- left-margin 1) - - Width of left margin minus width of 2 characters in the current font: - (- left-margin (2 . width)) - - Width of left fringe plus left margin minus one pixel: - (- (+ left-fringe left-margin) (1)) - (+ left-fringe left-margin (- (1))) - (+ left-fringe left-margin (-1)) - -*/ - -#define NUMVAL(X) \ - ((INTEGERP (X) || FLOATP (X)) \ - ? XFLOATINT (X) \ - : - 1) - -static int -calc_pixel_width_or_height (res, it, prop, font, width_p) - double *res; - struct it *it; - Lisp_Object prop; - XFontStruct *font; - int width_p; -{ - double pixels; - -#define OK_PIXELS(val) ((*res = (val)), 1) - - if (SYMBOLP (prop)) - { - if (SCHARS (SYMBOL_NAME (prop)) == 2) - { - char *unit = SDATA (SYMBOL_NAME (prop)); - - if (unit[0] == 'i' && unit[1] == 'n') - pixels = 1.0; - else if (unit[0] == 'm' && unit[1] == 'm') - pixels = 25.4; - else if (unit[0] == 'c' && unit[1] == 'm') - pixels = 2.54; - else - pixels = 0; - if (pixels > 0) - { - double ppi; - if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0) - || (CONSP (Vdisplay_pixels_per_inch) - && (ppi = (width_p - ? NUMVAL (XCAR (Vdisplay_pixels_per_inch)) - : NUMVAL (XCDR (Vdisplay_pixels_per_inch))), - ppi > 0))) - return OK_PIXELS (ppi / pixels); - - return 0; - } - } - - if (EQ (prop, Qheight)) - return OK_PIXELS (font ? FONT_HEIGHT (font) : FRAME_LINE_HEIGHT (it->f)); - if (EQ (prop, Qwidth)) - return OK_PIXELS (font ? FONT_WIDTH (font) : FRAME_COLUMN_WIDTH (it->f)); - if (EQ (prop, Qleft_fringe)) - return OK_PIXELS (WINDOW_LEFT_FRINGE_WIDTH (it->w)); - if (EQ (prop, Qright_fringe)) - return OK_PIXELS (WINDOW_RIGHT_FRINGE_WIDTH (it->w)); - if (EQ (prop, Qleft_margin)) - return OK_PIXELS (WINDOW_LEFT_MARGIN_WIDTH (it->w)); - if (EQ (prop, Qright_margin)) - return OK_PIXELS (WINDOW_RIGHT_MARGIN_WIDTH (it->w)); - if (EQ (prop, Qscroll_bar)) - return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w)); - - prop = Fbuffer_local_value (prop, it->w->buffer); - } - - if (INTEGERP (prop) || FLOATP (prop)) - { - int base_unit = (width_p - ? FRAME_COLUMN_WIDTH (it->f) - : FRAME_LINE_HEIGHT (it->f)); - return OK_PIXELS (XFLOATINT (prop) * base_unit); - } - - if (CONSP (prop)) - { - Lisp_Object car = XCAR (prop); - Lisp_Object cdr = XCDR (prop); - - if (SYMBOLP (car)) - { - if (EQ (car, Qplus) || EQ (car, Qminus)) - { - int first = 1; - double px; - - pixels = 0; - while (CONSP (cdr)) - { - if (!calc_pixel_width_or_height (&px, it, XCAR (cdr), font, width_p)) - return 0; - if (first) - pixels = (EQ (car, Qplus) ? px : -px), first = 0; - else - pixels += px; - cdr = XCDR (cdr); - } - if (EQ (car, Qminus)) - pixels = -pixels; - return OK_PIXELS (pixels); - } - - if (EQ (car, Qleft_fringe)) - return OK_PIXELS ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) - == !NILP (cdr)) - ? WINDOW_LEFT_FRINGE_WIDTH (it->w) - : 0); - if (EQ (car, Qright_fringe)) - return OK_PIXELS ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) - == !NILP (cdr)) - ? WINDOW_RIGHT_FRINGE_WIDTH (it->w) - : 0); - if (EQ (car, Qscroll_bar)) - return OK_PIXELS ((WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w) - == EQ (cdr, Qleft)) - ? WINDOW_SCROLL_BAR_AREA_WIDTH (it->w) - : 0); - - car = Fbuffer_local_value (car, it->w->buffer); - } - - if (INTEGERP (car) || FLOATP (car)) - { - double fact; - pixels = XFLOATINT (car); - if (NILP (cdr)) - return OK_PIXELS (pixels); - if (calc_pixel_width_or_height (&fact, it, cdr, font, width_p)) - return OK_PIXELS (pixels * fact); - return 0; - } - - return 0; - } - - return 0; -} - /* Produce a stretch glyph for iterator IT. IT->object is the value of the glyph property displayed. The value must be a list `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs @@ -18019,7 +18282,7 @@ produce_stretch_glyph (it) { /* (space :width WIDTH :height HEIGHT ...) */ Lisp_Object prop, plist; - int width = 0, height = 0; + int width = 0, height = 0, align_to = -1; int zero_width_ok_p = 0, zero_height_ok_p = 0; int ascent = 0; double tem; @@ -18034,7 +18297,7 @@ produce_stretch_glyph (it) /* Compute the width of the stretch. */ if ((prop = Fplist_get (plist, QCwidth), !NILP (prop)) - && calc_pixel_width_or_height (&tem, it, prop, font, 1)) + && calc_pixel_width_or_height (&tem, it, prop, font, 1, 0)) { /* Absolute width `:width WIDTH' specified and valid. */ zero_width_ok_p = 1; @@ -18065,9 +18328,15 @@ produce_stretch_glyph (it) width = NUMVAL (prop) * it2.pixel_width; } else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop)) - && calc_pixel_width_or_height (&tem, it, prop, font, 1)) - { - width = max (0, (int)tem - it->current_x); + && calc_pixel_width_or_height (&tem, it, prop, font, 1, &align_to)) + { + if (it->glyph_row == NULL || !it->glyph_row->mode_line_p) + align_to = (align_to < 0 + ? 0 + : align_to - window_box_left_offset (it->w, TEXT_AREA)); + else if (align_to < 0) + align_to = window_box_left_offset (it->w, TEXT_AREA); + width = max (0, (int)tem + align_to - it->current_x); zero_width_ok_p = 1; } else @@ -18079,7 +18348,7 @@ produce_stretch_glyph (it) /* Compute height. */ if ((prop = Fplist_get (plist, QCheight), !NILP (prop)) - && calc_pixel_width_or_height (&tem, it, prop, font, 0)) + && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0)) { height = (int)tem; zero_height_ok_p = 1; @@ -18100,7 +18369,7 @@ produce_stretch_glyph (it) NUMVAL (prop) > 0 && NUMVAL (prop) <= 100) ascent = height * NUMVAL (prop) / 100.0; else if (!NILP (prop) - && calc_pixel_width_or_height (&tem, it, prop, font, 0)) + && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0)) ascent = min (max (0, (int)tem), height); else ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font); @@ -18219,8 +18488,8 @@ x_produce_glyphs (it) it->nglyphs = 1; - pcm = rif->per_char_metric (font, &char2b, - FONT_TYPE_FOR_UNIBYTE (font, it->char_to_display)); + pcm = FRAME_RIF (it->f)->per_char_metric (font, &char2b, + FONT_TYPE_FOR_UNIBYTE (font, it->char_to_display)); it->ascent = FONT_BASE (font) + boff; it->descent = FONT_DESCENT (font) - boff; @@ -18344,8 +18613,8 @@ x_produce_glyphs (it) from the charset width; this is what old redisplay code did. */ - pcm = rif->per_char_metric (font, &char2b, - FONT_TYPE_FOR_MULTIBYTE (font, it->c)); + pcm = FRAME_RIF (it->f)->per_char_metric (font, &char2b, + FONT_TYPE_FOR_MULTIBYTE (font, it->c)); if (font_not_found_p || !pcm) { @@ -18476,8 +18745,8 @@ x_produce_glyphs (it) /* Initialize the bounding box. */ if (font_info - && (pcm = rif->per_char_metric (font, &char2b, - FONT_TYPE_FOR_MULTIBYTE (font, it->c)))) + && (pcm = FRAME_RIF (it->f)->per_char_metric (font, &char2b, + FONT_TYPE_FOR_MULTIBYTE (font, it->c)))) { width = pcm->width; ascent = pcm->ascent; @@ -18535,8 +18804,8 @@ x_produce_glyphs (it) } if (font_info - && (pcm = rif->per_char_metric (font, &char2b, - FONT_TYPE_FOR_MULTIBYTE (font, ch)))) + && (pcm = FRAME_RIF (it->f)->per_char_metric (font, &char2b, + FONT_TYPE_FOR_MULTIBYTE (font, ch)))) { width = pcm->width; ascent = pcm->ascent; @@ -18771,8 +19040,8 @@ x_insert_glyphs (start, len) frame_x = window_box_left (w, updated_area) + output_cursor.x; frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y); - rif->shift_glyphs_for_insert (f, frame_x, frame_y, shifted_region_width, - line_height, shift_by_width); + FRAME_RIF (f)->shift_glyphs_for_insert (f, frame_x, frame_y, shifted_region_width, + line_height, shift_by_width); /* Write the glyphs. */ hpos = start - row->glyphs[updated_area]; @@ -18854,8 +19123,8 @@ x_clear_end_of_line (to_x) if (to_x > from_x && to_y > from_y) { BLOCK_INPUT; - rif->clear_frame_area (f, from_x, from_y, - to_x - from_x, to_y - from_y); + FRAME_RIF (f)->clear_frame_area (f, from_x, from_y, + to_x - from_x, to_y - from_y); UNBLOCK_INPUT; } } @@ -19317,8 +19586,8 @@ erase_phys_cursor (w) x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); y = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, cursor_row->y)); - rif->clear_frame_area (f, x, y, - cursor_glyph->pixel_width, cursor_row->visible_height); + FRAME_RIF (f)->clear_frame_area (f, x, y, + cursor_glyph->pixel_width, cursor_row->visible_height); } /* Erase the cursor by redrawing the character underneath it. */ @@ -19415,9 +19684,9 @@ display_and_set_cursor (w, on, hpos, vpos, x, y) w->phys_cursor.vpos = vpos; } - rif->draw_window_cursor (w, glyph_row, x, y, - new_cursor_type, new_cursor_width, - on, active_cursor); + FRAME_RIF (f)->draw_window_cursor (w, glyph_row, x, y, + new_cursor_type, new_cursor_width, + on, active_cursor); } @@ -19562,11 +19831,11 @@ show_mouse_face (dpyinfo, draw) /* Change the mouse cursor. */ if (draw == DRAW_NORMAL_TEXT) - rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->text_cursor); + FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->text_cursor); else if (draw == DRAW_MOUSE_FACE) - rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->hand_cursor); + FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->hand_cursor); else - rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->nontext_cursor); + FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->nontext_cursor); } /* EXPORT: @@ -19580,7 +19849,7 @@ clear_mouse_face (dpyinfo) { int cleared = 0; - if (!NILP (dpyinfo->mouse_face_window)) + if (!dpyinfo->mouse_face_hidden && !NILP (dpyinfo->mouse_face_window)) { show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT); cleared = 1; @@ -19945,7 +20214,7 @@ on_hot_spot_p (hot_spot, x, y) int x0, y0; /* Need an even number of coordinates, and at least 3 edges. */ - if (n < 6 || n & 1) + if (n < 6 || n & 1) return 0; /* Count edge segments intersecting line from (X,Y) to (X,infinity). @@ -19980,8 +20249,7 @@ on_hot_spot_p (hot_spot, x, y) return inside; } } - else - return 0; + return 0; } Lisp_Object @@ -19996,13 +20264,13 @@ find_hot_spot (map, x, y) return XCAR (map); map = XCDR (map); } - + return Qnil; } DEFUN ("lookup-image-map", Flookup_image_map, Slookup_image_map, 3, 3, 0, - doc: /* Lookup in image map MAP coordinates X and Y. + doc: /* Lookup in image map MAP coordinates X and Y. An image map is an alist where each element has the format (AREA ID PLIST). An AREA is specified as either a rectangle, a circle, or a polygon: A rectangle is a cons (rect . ((x0 . y0) . (x1 . y1))) specifying the @@ -20016,7 +20284,6 @@ Returns the alist element for the first matching AREA in MAP. */) Lisp_Object map; Lisp_Object x, y; { - int ix, iy; if (NILP (map)) return Qnil; @@ -20061,7 +20328,7 @@ define_frame_cursor1 (f, cursor, pointer) #else if (bcmp (&cursor, &No_Cursor, sizeof (Cursor))) #endif - rif->define_frame_cursor (f, cursor); + FRAME_RIF (f)->define_frame_cursor (f, cursor); } /* Take proper action when mouse has moved to the mode or header line @@ -20082,7 +20349,7 @@ note_mode_line_or_margin_highlight (w, x, y, area) Lisp_Object pointer = Qnil; int charpos, dx, dy, width, height; Lisp_Object string, object = Qnil; - Lisp_Object pos, help, image; + Lisp_Object pos, help; if (area == ON_MODE_LINE || area == ON_HEADER_LINE) string = mode_line_string (w, area, &x, &y, &charpos, @@ -20150,7 +20417,7 @@ note_mode_line_or_margin_highlight (w, x, y, area) pointer = Fget_text_property (pos, Qpointer, string); /* Change the mouse pointer according to what is under X/Y. */ - if (NILP (pointer) && area == ON_MODE_LINE) + if (NILP (pointer) && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))) { Lisp_Object map; map = Fget_text_property (pos, Qlocal_map, string); @@ -20876,13 +21143,13 @@ phys_cursor_in_rect_p (w, r) cursor_glyph = get_phys_cursor_glyph (w); if (cursor_glyph) { - /* r is relative to W's box, but w->phys_cursor.x is relative + /* r is relative to W's box, but w->phys_cursor.x is relative to left edge of W's TEXT area. Adjust it. */ cr.x = window_box_left_offset (w, TEXT_AREA) + w->phys_cursor.x; cr.y = w->phys_cursor.y; cr.width = cursor_glyph->pixel_width; cr.height = w->phys_cursor_height; - /* ++KFS: W32 version used W32-specific IntersectRect here, but + /* ++KFS: W32 version used W32-specific IntersectRect here, but I assume the effect is the same -- and this is portable. */ return x_intersect_rectangles (&cr, r, &result); } @@ -20899,8 +21166,10 @@ void x_draw_vertical_border (w) struct window *w; { + struct frame *f = XFRAME (WINDOW_FRAME (w)); + /* We could do better, if we knew what type of scroll-bar the adjacent - windows (on either side) have... But we don't :-( + windows (on either side) have... But we don't :-( However, I think this works ok. ++KFS 2003-04-25 */ /* Redraw borders between horizontally adjacent windows. Don't @@ -20915,7 +21184,7 @@ x_draw_vertical_border (w) window_box_edges (w, -1, &x0, &y0, &x1, &y1); y1 -= 1; - rif->draw_vertical_window_border (w, x1, y0, y1); + FRAME_RIF (f)->draw_vertical_window_border (w, x1, y0, y1); } else if (!WINDOW_LEFTMOST_P (w) && !WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)) @@ -20925,7 +21194,7 @@ x_draw_vertical_border (w) window_box_edges (w, -1, &x0, &y0, &x1, &y1); y1 -= 1; - rif->draw_vertical_window_border (w, x0, y0, y1); + FRAME_RIF (f)->draw_vertical_window_border (w, x0, y0, y1); } } @@ -21324,6 +21593,8 @@ syms_of_xdisp () staticpro (&Qleft_margin); Qright_margin = intern ("right-margin"); staticpro (&Qright_margin); + Qcenter = intern ("center"); + staticpro (&Qcenter); QCalign_to = intern (":align-to"); staticpro (&QCalign_to); QCrelative_width = intern (":relative-width"); @@ -21389,13 +21660,20 @@ syms_of_xdisp () Qinhibit_free_realized_faces = intern ("inhibit-free-realized-faces"); staticpro (&Qinhibit_free_realized_faces); - list_of_error = Fcons (intern ("error"), Qnil); + list_of_error = Fcons (Fcons (intern ("error"), + Fcons (intern ("void-variable"), Qnil)), + Qnil); staticpro (&list_of_error); - last_arrow_position = Qnil; - last_arrow_string = Qnil; - staticpro (&last_arrow_position); - staticpro (&last_arrow_string); + Qlast_arrow_position = intern ("last-arrow-position"); + staticpro (&Qlast_arrow_position); + Qlast_arrow_string = intern ("last-arrow-string"); + staticpro (&Qlast_arrow_string); + + Qoverlay_arrow_string = intern ("overlay-arrow-string"); + staticpro (&Qoverlay_arrow_string); + Qoverlay_arrow_bitmap = intern ("overlay-arrow-bitmap"); + staticpro (&Qoverlay_arrow_bitmap); echo_buffer[0] = echo_buffer[1] = Qnil; staticpro (&echo_buffer[0]); @@ -21440,7 +21718,7 @@ The face used for trailing whitespace is `trailing-whitespace'. */); DEFVAR_LISP ("void-text-area-pointer", &Vvoid_text_area_pointer, doc: /* *The pointer shape to show in void text areas. Nil means to show the text pointer. Other options are `arrow', `text', -`hand', `vdrag', `hdrag', `modeline', and `hourglass'. */); +`hand', `vdrag', `hdrag', `modeline', and `hourglass'. */); Vvoid_text_area_pointer = Qarrow; DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay, @@ -21459,9 +21737,17 @@ See also `overlay-arrow-string'. */); Voverlay_arrow_position = Qnil; DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string, - doc: /* String to display as an arrow. See also `overlay-arrow-position'. */); + doc: /* String to display as an arrow in non-window frames. +See also `overlay-arrow-position'. */); Voverlay_arrow_string = Qnil; + DEFVAR_LISP ("overlay-arrow-variable-list", &Voverlay_arrow_variable_list, + doc: /* List of variables (symbols) which hold markers for overlay arrows. +The symbols on this list are examined during redisplay to determine +where to display overlay arrows. */); + Voverlay_arrow_variable_list + = Fcons (intern ("overlay-arrow-position"), Qnil); + DEFVAR_INT ("scroll-step", &scroll_step, doc: /* *The number of lines to try scrolling a window by when point moves out. If that fails to bring point back on frame, point is centered instead.