X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/351b5434f9c4a242fdc5494ee8d0128f5baa4120..d58f8753fb07765becc40b53bcb1f48e20c1483a:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index 7fbe6c1b93..f51727d34d 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -301,6 +301,8 @@ 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 Qslice; +Lisp_Object Qcenter; Lisp_Object Qmargin, Qpointer; extern Lisp_Object Qheight; extern Lisp_Object QCwidth, QCheight, QCascent; @@ -314,7 +316,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) \ @@ -406,7 +408,7 @@ 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. */ + where to display overlay arrows. */ Lisp_Object Voverlay_arrow_variable_list; @@ -849,7 +851,7 @@ 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)); @@ -1234,9 +1236,9 @@ line_bottom_y (it) and header-lines heights. */ int -pos_visible_p (w, charpos, fully, exact_mode_line_heights_p) +pos_visible_p (w, charpos, fully, x, y, exact_mode_line_heights_p) struct window *w; - int charpos, *fully, exact_mode_line_heights_p; + int charpos, *fully, *x, *y, exact_mode_line_heights_p; { struct it it; struct text_pos top; @@ -1284,14 +1286,27 @@ pos_visible_p (w, charpos, fully, exact_mode_line_heights_p) visible_p = 1; *fully = bottom_y <= it.last_visible_y; } + if (visible_p && x) + { + *x = it.current_x; + *y = max (top_y + it.max_ascent - it.ascent, window_top_y); + } } else if (it.current_y + it.max_ascent + it.max_descent > it.last_visible_y) { + struct it it2; + + it2 = it; move_it_by_lines (&it, 1, 0); if (charpos < IT_CHARPOS (it)) { visible_p = 1; - *fully = 0; + if (x) + { + move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS); + *x = it2.current_x; + *y = it2.current_y + it2.max_ascent - it2.ascent; + } } } @@ -1299,6 +1314,7 @@ pos_visible_p (w, charpos, fully, exact_mode_line_heights_p) set_buffer_internal_1 (old_buffer); current_header_line_height = current_mode_line_height = -1; + return visible_p; } @@ -1792,8 +1808,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); } } @@ -2065,7 +2082,8 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) if (FRAME_FACE_CACHE (it->f)->used == 0) recompute_basic_faces (it->f); - /* Current value of the `space-width', and 'height' properties. */ + /* Current value of the `slice', `space-width', and 'height' properties. */ + it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil; it->space_width = Qnil; it->font_height = Qnil; @@ -3273,8 +3291,9 @@ handle_display_prop (it) } /* Reset those iterator values set from display property values. */ - it->font_height = Qnil; + it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil; it->space_width = Qnil; + it->font_height = Qnil; it->voffset = 0; /* We don't support recursive `display' properties, i.e. string @@ -3293,6 +3312,7 @@ handle_display_prop (it) && !EQ (XCAR (prop), Qimage) && !EQ (XCAR (prop), Qspace) && !EQ (XCAR (prop), Qwhen) + && !EQ (XCAR (prop), Qslice) && !EQ (XCAR (prop), Qspace_width) && !EQ (XCAR (prop), Qheight) && !EQ (XCAR (prop), Qraise) @@ -3488,6 +3508,30 @@ handle_single_display_prop (it, prop, object, position, if (NUMBERP (value) && XFLOATINT (value) > 0) it->space_width = value; } + else if (CONSP (prop) + && EQ (XCAR (prop), Qslice)) + { + /* `(slice X Y WIDTH HEIGHT)'. */ + Lisp_Object tem; + + if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f)) + return 0; + + if (tem = XCDR (prop), CONSP (tem)) + { + it->slice.x = XCAR (tem); + if (tem = XCDR (tem), CONSP (tem)) + { + it->slice.y = XCAR (tem); + if (tem = XCDR (tem), CONSP (tem)) + { + it->slice.width = XCAR (tem); + if (tem = XCDR (tem), CONSP (tem)) + it->slice.height = XCAR (tem); + } + } + } + } else if (CONSP (prop) && EQ (XCAR (prop), Qraise) && CONSP (XCDR (prop))) @@ -3607,16 +3651,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) @@ -4334,6 +4373,7 @@ push_it (it) p->string_nchars = it->string_nchars; p->area = it->area; p->multibyte_p = it->multibyte_p; + p->slice = it->slice; p->space_width = it->space_width; p->font_height = it->font_height; p->voffset = it->voffset; @@ -4366,6 +4406,7 @@ pop_it (it) it->string_nchars = p->string_nchars; it->area = p->area; it->multibyte_p = p->multibyte_p; + it->slice = p->slice; it->space_width = p->space_width; it->font_height = p->font_height; it->voffset = p->voffset; @@ -5598,15 +5639,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; @@ -5693,7 +5737,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; @@ -5765,7 +5810,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; @@ -5782,6 +5828,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; @@ -8364,7 +8412,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); @@ -9420,15 +9468,15 @@ update_overlay_arrows (up_to_date) vlist = XCDR (vlist)) { Lisp_Object var = XCAR (vlist); - Lisp_Object val; if (!SYMBOLP (var)) continue; - if (up_to_date) + if (up_to_date > 0) { + Lisp_Object val = find_symbol_value (var); Fput (var, Qlast_arrow_position, - COERCE_MARKER (find_symbol_value (var))); + COERCE_MARKER (val)); Fput (var, Qlast_arrow_string, overlay_arrow_string_or_property (var, 0)); } @@ -9463,7 +9511,7 @@ overlay_arrow_at_row (f, row, pbitmap) continue; val = find_symbol_value (var); - + if (MARKERP (val) && current_buffer == XMARKER (val)->buffer && (MATRIX_ROW_START_CHARPOS (row) == marker_position (val))) @@ -9570,7 +9618,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)) @@ -10730,12 +10778,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; @@ -10757,8 +10810,10 @@ make_cursor_line_fully_visible (w) it's not clear what to do, so do nothing. */ window_height = window_box_height (w); if (row->height >= window_height) - return 1; - + { + if (!force_p || w->vscroll) + return 1; + } return 0; #if 0 @@ -10849,7 +10904,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"); @@ -10867,6 +10922,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) @@ -10892,11 +10953,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; } @@ -11031,10 +11094,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; @@ -11323,7 +11386,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; @@ -11353,7 +11416,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) @@ -11365,7 +11428,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)) @@ -11654,7 +11717,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. */ @@ -11791,7 +11854,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; @@ -11951,7 +12014,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) @@ -11964,6 +12027,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; } @@ -14133,8 +14197,12 @@ append_space (it, default_face_p) face = FACE_FROM_ID (it->f, it->face_id); it->face_id = FACE_FOR_CHAR (it->f, face, 0); + if (it->max_ascent > 0 || it->max_descent > 0) + it->constrain_row_ascent_descent_p = 1; + PRODUCE_GLYPHS (it); + it->constrain_row_ascent_descent_p = 0; it->current_x = saved_x; it->object = saved_object; it->position = saved_pos; @@ -14749,15 +14817,15 @@ display_line (it) This is clearly a mess with variable size fonts. It would be better to let it be displayed like cursors under X. */ if (! overlay_arrow_seen - && (overlay_arrow_string = overlay_arrow_at_row (it->f, row, - &overlay_arrow_bitmap), + && (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, overlay_arrow_bitmap); + = 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]; @@ -15065,6 +15133,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; @@ -15081,7 +15151,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; @@ -16695,6 +16764,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 @@ -17034,6 +17349,7 @@ fill_image_glyph_string (s) xassert (s->first_glyph->type == IMAGE_GLYPH); s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id); xassert (s->img); + s->slice = s->first_glyph->slice; s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id); s->font = s->face->font; s->width = s->first_glyph->pixel_width; @@ -17832,7 +18148,7 @@ take_vertical_position_into_account (it) if (it->voffset < 0) /* Increase the ascent so that we can display the text higher in the line. */ - it->ascent += abs (it->voffset); + it->ascent -= it->voffset; else /* Increase the descent so that we can display the text lower in the line. */ @@ -17852,6 +18168,7 @@ produce_image_glyph (it) struct image *img; struct face *face; int face_ascent, glyph_ascent; + struct glyph_slice slice; xassert (it->what == IT_IMAGE); @@ -17875,19 +18192,68 @@ produce_image_glyph (it) /* 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; + slice.x = slice.y = 0; + slice.width = img->width; + slice.height = img->height; + + if (INTEGERP (it->slice.x)) + slice.x = XINT (it->slice.x); + else if (FLOATP (it->slice.x)) + slice.x = XFLOAT_DATA (it->slice.x) * img->width; + + if (INTEGERP (it->slice.y)) + slice.y = XINT (it->slice.y); + else if (FLOATP (it->slice.y)) + slice.y = XFLOAT_DATA (it->slice.y) * img->height; + + if (INTEGERP (it->slice.width)) + slice.width = XINT (it->slice.width); + else if (FLOATP (it->slice.width)) + slice.width = XFLOAT_DATA (it->slice.width) * img->width; + + if (INTEGERP (it->slice.height)) + slice.height = XINT (it->slice.height); + else if (FLOATP (it->slice.height)) + slice.height = XFLOAT_DATA (it->slice.height) * img->height; + + if (slice.x >= img->width) + slice.x = img->width; + if (slice.y >= img->height) + slice.y = img->height; + if (slice.x + slice.width >= img->width) + slice.width = img->width - slice.x; + if (slice.y + slice.height > img->height) + slice.height = img->height - slice.y; + + if (slice.width == 0 || slice.height == 0) + return; + + it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face, &slice); + + it->descent = slice.height - glyph_ascent; + if (slice.y == 0) + it->descent += img->vmargin; + if (slice.y + slice.height == img->height) + it->descent += img->vmargin; + it->phys_descent = it->descent; + + it->pixel_width = slice.width; + if (slice.x == 0) + it->pixel_width += img->hmargin; + if (slice.x + slice.width == img->width) + it->pixel_width += 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 0 /* this breaks image tiling */ /* 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) it->ascent = it->phys_ascent = face_ascent; +#endif it->nglyphs = 1; @@ -17895,13 +18261,15 @@ produce_image_glyph (it) { if (face->box_line_width > 0) { - it->ascent += face->box_line_width; - it->descent += face->box_line_width; + if (slice.y == 0) + it->ascent += face->box_line_width; + if (slice.y + slice.height == img->height) + it->descent += face->box_line_width; } - if (it->start_of_box_run_p) + if (it->start_of_box_run_p && slice.x == 0) it->pixel_width += abs (face->box_line_width); - if (it->end_of_box_run_p) + if (it->end_of_box_run_p && slice.x + slice.width == img->width) it->pixel_width += abs (face->box_line_width); } @@ -17930,6 +18298,7 @@ produce_image_glyph (it) glyph->glyph_not_available_p = 0; glyph->face_id = it->face_id; glyph->u.img_id = img->id; + glyph->slice = slice; glyph->font_type = FONT_TYPE_UNKNOWN; ++it->glyph_row->used[area]; } @@ -17978,209 +18347,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 @@ -18218,7 +18384,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; @@ -18233,7 +18399,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; @@ -18264,9 +18430,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 @@ -18278,7 +18450,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; @@ -18299,7 +18471,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); @@ -18420,6 +18592,7 @@ x_produce_glyphs (it) pcm = rif->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; @@ -18432,11 +18605,27 @@ x_produce_glyphs (it) else { it->glyph_not_available_p = 1; - it->phys_ascent = FONT_BASE (font) + boff; - it->phys_descent = FONT_DESCENT (font) - boff; + it->phys_ascent = it->ascent; + it->phys_descent = it->descent; it->pixel_width = FONT_WIDTH (font); } + if (it->constrain_row_ascent_descent_p) + { + if (it->descent > it->max_descent) + { + it->ascent += it->descent - it->max_descent; + it->descent = it->max_descent; + } + if (it->ascent> it->max_ascent) + { + it->descent = min (it->max_descent, it->descent + it->ascent - it->max_ascent); + it->ascent = it->max_ascent; + } + it->phys_ascent = min (it->phys_ascent, it->ascent); + it->phys_descent = min (it->phys_descent, it->descent); + } + /* If this is a space inside a region of text with `space-width' property, change its width. */ stretched_p = it->char_to_display == ' ' && !NILP (it->space_width); @@ -18469,6 +18658,14 @@ x_produce_glyphs (it) if (face->overline_p) it->ascent += 2; + if (it->constrain_row_ascent_descent_p) + { + if (it->ascent > it->max_ascent) + it->ascent = it->max_ascent; + if (it->descent > it->max_descent) + it->descent = it->max_descent; + } + take_vertical_position_into_account (it); /* If we have to actually produce glyphs, do it. */ @@ -18495,13 +18692,31 @@ x_produce_glyphs (it) } else if (it->char_to_display == '\n') { - /* A newline has no width but we need the height of the line. */ + /* A newline has no width but we need the height of the line. + But if previous part of the line set a height, don't + increase that height */ + it->pixel_width = 0; it->nglyphs = 0; - it->ascent = it->phys_ascent = FONT_BASE (font) + boff; - it->descent = it->phys_descent = FONT_DESCENT (font) - boff; - if (face->box != FACE_NO_BOX + it->ascent = FONT_BASE (font) + boff; + it->descent = FONT_DESCENT (font) - boff; + + if (it->max_ascent > 0 || it->max_descent > 0) + { + it->ascent = it->descent = 0; + } + else + { + it->ascent = FONT_BASE (font) + boff; + it->descent = FONT_DESCENT (font) - boff; + } + + it->phys_ascent = it->ascent; + it->phys_descent = it->descent; + + if ((it->max_ascent > 0 || it->max_descent > 0) + && face->box != FACE_NO_BOX && face->box_line_width > 0) { it->ascent += face->box_line_width; @@ -19779,7 +19994,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; @@ -20144,7 +20359,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). @@ -20195,13 +20410,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 @@ -20349,7 +20564,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); @@ -20476,7 +20691,9 @@ note_mouse_highlight (f, x, y) Lisp_Object image_map, hotspot; if ((image_map = Fplist_get (XCDR (img->spec), QCmap), !NILP (image_map)) - && (hotspot = find_hot_spot (image_map, dx, dy), + && (hotspot = find_hot_spot (image_map, + glyph->slice.x + dx, + glyph->slice.y + dy), CONSP (hotspot)) && (hotspot = XCDR (hotspot), CONSP (hotspot))) { @@ -21075,13 +21292,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); } @@ -21099,7 +21316,7 @@ x_draw_vertical_border (w) struct window *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 @@ -21513,6 +21730,8 @@ syms_of_xdisp () staticpro (&Qspace_width); Qraise = intern ("raise"); staticpro (&Qraise); + Qslice = intern ("slice"); + staticpro (&Qslice); Qspace = intern ("space"); staticpro (&Qspace); Qmargin = intern ("margin"); @@ -21523,6 +21742,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"); @@ -21588,7 +21809,9 @@ 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); Qlast_arrow_position = intern ("last-arrow-position"); @@ -21644,7 +21867,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,