X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/057a9ab495a5fd334f9bd3c7704176502e5219c4..6ad9aaa961f1ac376bdaa1a5516d0481e6c7fafa:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index 67f2144632..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. */ @@ -828,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)); @@ -1774,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); } } @@ -3589,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) @@ -5580,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; @@ -5675,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; @@ -5747,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; @@ -5764,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; @@ -8346,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); @@ -9316,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. */ @@ -9595,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 @@ -10056,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. */ @@ -10076,8 +10236,8 @@ 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_DISPLAY (sf)->frame_up_to_date_hook != 0) FRAME_DISPLAY (sf)->frame_up_to_date_hook (sf); @@ -10273,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); } } @@ -10572,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; @@ -10595,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); @@ -10691,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"); @@ -10709,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) @@ -10734,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; } @@ -10873,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; @@ -11033,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; @@ -11166,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; @@ -11196,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) @@ -11208,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)) @@ -11499,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. */ @@ -11636,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; @@ -11796,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) @@ -11809,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; } @@ -12786,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); @@ -13180,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 (!FRAME_SCROLL_REGION_OK (f)) - ins_del_lines (end - dvpos, -dvpos); + 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 (!FRAME_SCROLL_REGION_OK (f)) - ins_del_lines (end + dvpos, -dvpos); + ins_del_lines (f, end + dvpos, -dvpos); } - set_terminal_window (0); + set_terminal_window (f, 0); } update_end (f); @@ -13724,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; @@ -13758,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. */ @@ -14197,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); @@ -14592,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]; @@ -14626,6 +14801,7 @@ display_line (it) } overlay_arrow_seen = 1; + it->w->overlay_arrow_bitmap = overlay_arrow_bitmap; row->overlay_arrow_p = 1; } @@ -14909,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; @@ -14925,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; @@ -16539,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 @@ -17707,6 +18130,9 @@ produce_image_glyph (it) 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; } @@ -17819,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 @@ -18059,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; @@ -18074,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; @@ -18105,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 @@ -18119,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; @@ -18140,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); @@ -19620,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; @@ -19985,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). @@ -20035,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 @@ -20055,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; @@ -20121,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, @@ -20189,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); @@ -20915,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); } @@ -20941,7 +21169,7 @@ x_draw_vertical_border (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 @@ -21365,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"); @@ -21430,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]); @@ -21481,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, @@ -21500,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.