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;
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) \
/* 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;
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));
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;
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;
+ }
}
}
set_buffer_internal_1 (old_buffer);
current_header_line_height = current_mode_line_height = -1;
+
return visible_p;
}
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);
}
}
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;
}
/* 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
&& !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)
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)))
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)
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;
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;
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;
#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;
#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;
}
}
+#undef BUFFER_POS_REACHED_P
+
/* Restore the iterator settings altered at the beginning of this
function. */
it->glyph_row = saved_glyph_row;
/* 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);
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));
}
continue;
val = find_symbol_value (var);
-
+
if (MARKERP (val)
&& current_buffer == XMARKER (val)->buffer
&& (MATRIX_ROW_START_CHARPOS (row) == marker_position (val)))
{
Lisp_Object tail, sym, val;
Lisp_Object old = selected_frame;
-
+
selected_frame = frame;
for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail))
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;
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
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");
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)
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;
}
/* 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;
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;
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)
/* 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))
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. */
/* 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;
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)
/* 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;
}
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;
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];
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;
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;
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;
+}
+
\f
/***********************************************************************
Glyph Display
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;
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. */
struct image *img;
struct face *face;
int face_ascent, glyph_ascent;
+ struct glyph_slice slice;
xassert (it->what == IT_IMAGE);
/* 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;
{
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);
}
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];
}
}
-/* 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
{
/* (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;
/* 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;
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
/* 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;
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);
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;
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);
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. */
}
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;
{
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;
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).
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
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);
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)))
{
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);
}
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
staticpro (&Qspace_width);
Qraise = intern ("raise");
staticpro (&Qraise);
+ Qslice = intern ("slice");
+ staticpro (&Qslice);
Qspace = intern ("space");
staticpro (&Qspace);
Qmargin = intern ("margin");
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");
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");
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,