/* Display generation from window structure and buffer text.
Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995,
1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005 Free Software Foundation, Inc.
+ 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Emacs.
int make_cursor_line_fully_visible_p;
+/* Margin below tool bar in pixels. 0 or nil means no margin.
+ If value is `internal-border-width' or `border-width',
+ the corresponding frame parameter is used. */
+
+Lisp_Object Vtool_bar_border;
+
/* Margin around tool bar buttons in pixels. */
Lisp_Object Vtool_bar_button_margin;
static int store_mode_line_noprop P_ ((const unsigned char *, int, int));
static void x_consider_frame_title P_ ((Lisp_Object));
static void handle_stop P_ ((struct it *));
-static int tool_bar_lines_needed P_ ((struct frame *));
+static int tool_bar_lines_needed P_ ((struct frame *, int *));
static int single_display_spec_intangible_p P_ ((Lisp_Object));
static void ensure_echo_area_buffers P_ ((void));
static Lisp_Object unwind_with_echo_area_buffer P_ ((Lisp_Object));
static void compute_line_metrics P_ ((struct it *));
static void run_redisplay_end_trigger_hook P_ ((struct it *));
static int get_overlay_strings P_ ((struct it *, int));
+static int get_overlay_strings_1 P_ ((struct it *, int, int));
static void next_overlay_string P_ ((struct it *));
static void reseat P_ ((struct it *, struct text_pos, int));
static void reseat_1 P_ ((struct it *, struct text_pos, int));
static void update_tool_bar P_ ((struct frame *, int));
static void build_desired_tool_bar_string P_ ((struct frame *f));
static int redisplay_tool_bar P_ ((struct frame *));
-static void display_tool_bar_line P_ ((struct it *));
+static void display_tool_bar_line P_ ((struct it *, int));
static void notice_overwritten_cursor P_ ((struct window *,
enum glyph_row_area,
int, int, int, int));
}
if ((s->for_overlaps & OVERLAPS_BOTH) == 0
- || (s->for_overlaps & OVERLAPS_BOTH) == OVERLAPS_BOTH && n == 1)
+ || ((s->for_overlaps & OVERLAPS_BOTH) == OVERLAPS_BOTH && n == 1))
{
#ifdef CONVERT_FROM_XRECT
CONVERT_FROM_XRECT (r, *rects);
{
rs[i] = r;
if (r.y + r.height > row_y)
- if (r.y < row_y)
- rs[i].height = row_y - r.y;
- else
- rs[i].height = 0;
+ {
+ if (r.y < row_y)
+ rs[i].height = row_y - r.y;
+ else
+ rs[i].height = 0;
+ }
i++;
}
if (s->for_overlaps & OVERLAPS_SUCC)
{
rs[i] = r;
if (r.y < row_y + s->row->visible_height)
- if (r.y + r.height > row_y + s->row->visible_height)
- {
- rs[i].y = row_y + s->row->visible_height;
- rs[i].height = r.y + r.height - rs[i].y;
- }
- else
- rs[i].height = 0;
+ {
+ if (r.y + r.height > row_y + s->row->visible_height)
+ {
+ rs[i].y = row_y + s->row->visible_height;
+ rs[i].height = r.y + r.height - rs[i].y;
+ }
+ else
+ rs[i].height = 0;
+ }
i++;
}
Set w->phys_cursor_width to width of phys cursor.
*/
-int
-get_phys_cursor_geometry (w, row, glyph, heightp)
+void
+get_phys_cursor_geometry (w, row, glyph, xp, yp, heightp)
struct window *w;
struct glyph_row *row;
struct glyph *glyph;
- int *heightp;
+ int *xp, *yp, *heightp;
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
- int y, wd, h, h0, y0;
+ int x, y, wd, h, h0, y0;
/* Compute the width of the rectangle to draw. If on a stretch
glyph, and `x-stretch-block-cursor' is nil, don't draw a
#ifdef HAVE_NTGUI
wd++; /* Why? */
#endif
+
+ x = w->phys_cursor.x;
+ if (x < 0)
+ {
+ wd += x;
+ x = 0;
+ }
+
if (glyph->type == STRETCH_GLYPH
&& !x_stretch_cursor_p)
wd = min (FRAME_COLUMN_WIDTH (f), wd);
}
}
- *heightp = h - 1;
- return WINDOW_TO_FRAME_PIXEL_Y (w, y);
+ *xp = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, x);
+ *yp = WINDOW_TO_FRAME_PIXEL_Y (w, y);
+ *heightp = h;
}
/*
also ``processed'' overlay strings at ZV. */
while (it->sp)
pop_it (it);
- it->current.overlay_string_index = -1;
- it->method = GET_FROM_BUFFER;
+ xassert (it->current.overlay_string_index == -1);
+ xassert (it->method == GET_FROM_BUFFER);
if (CHARPOS (pos->pos) == ZV)
it->overlay_strings_at_end_processed_p = 1;
}
if (handled == HANDLED_RECOMPUTE_PROPS)
break;
else if (handled == HANDLED_RETURN)
- return;
+ {
+ /* We still want to show before and after strings from
+ overlays even if the actual buffer text is replaced. */
+ if (!handle_overlay_change_p || it->sp > 1)
+ return;
+ if (!get_overlay_strings_1 (it, 0, 0))
+ return;
+ it->ignore_overlay_strings_at_pos_p = 1;
+ it->string_from_display_prop_p = 0;
+ handle_overlay_change_p = 0;
+ handled = HANDLED_RECOMPUTE_PROPS;
+ break;
+ }
else if (handled == HANDLED_OVERLAY_STRING_CONSUMED)
handle_overlay_change_p = 0;
}
skip starting with next_stop. */
if (invis_p)
IT_CHARPOS (*it) = next_stop;
+
+ /* If there are adjacent invisible texts, don't lose the
+ second one's ellipsis. */
+ if (invis_p == 2)
+ display_ellipsis_p = 1;
}
while (invis_p);
it->stack[it->sp - 1].display_ellipsis_p = display_ellipsis_p;
}
else if (display_ellipsis_p)
- setup_for_ellipsis (it, 0);
+ {
+ /* Make sure that the glyphs of the ellipsis will get
+ correct `charpos' values. If we would not update
+ it->position here, the glyphs would belong to the
+ last visible character _before_ the invisible
+ text, which confuses `set_cursor_from_row'.
+
+ We use the last invisible position instead of the
+ first because this way the cursor is always drawn on
+ the first "." of the ellipsis, whenever PT is inside
+ the invisible text. Otherwise the cursor would be
+ placed _after_ the ellipsis when the point is after the
+ first invisible character. */
+ if (!STRINGP (it->object))
+ {
+ it->position.charpos = IT_CHARPOS (*it) - 1;
+ it->position.bytepos = CHAR_TO_BYTE (it->position.charpos);
+ }
+ setup_for_ellipsis (it, 0);
+ }
}
}
{
it->method = GET_FROM_STRETCH;
it->object = value;
- it->current.pos = it->position = start_pos;
+ *position = it->position = start_pos;
}
#ifdef HAVE_WINDOW_SYSTEM
else
if (id >= 0)
{
+ struct composition *cmp = composition_table[id];
+
+ if (cmp->glyph_len == 0)
+ {
+ /* No glyph. */
+ if (STRINGP (it->string))
+ {
+ IT_STRING_CHARPOS (*it) = end;
+ IT_STRING_BYTEPOS (*it) = string_char_to_byte (it->string,
+ end);
+ }
+ else
+ {
+ IT_CHARPOS (*it) = end;
+ IT_BYTEPOS (*it) = CHAR_TO_BYTE (end);
+ }
+ return HANDLED_RECOMPUTE_PROPS;
+ }
+
+ it->stop_charpos = end;
+ push_it (it);
+
it->method = GET_FROM_COMPOSITION;
it->cmp_id = id;
it->cmp_len = COMPOSITION_LENGTH (prop);
it->len = (STRINGP (it->string)
? string_char_to_byte (it->string, end)
: CHAR_TO_BYTE (end)) - pos_byte;
- it->stop_charpos = end;
handled = HANDLED_RETURN;
}
}
int display_ellipsis_p = it->stack[it->sp - 1].display_ellipsis_p;
pop_it (it);
- xassert (it->stop_charpos >= BEGV
- && it->stop_charpos <= it->end_charpos);
- it->string = Qnil;
+ xassert (it->sp > 0
+ || it->method == GET_FROM_COMPOSITION
+ || (NILP (it->string)
+ && it->method == GET_FROM_BUFFER
+ && it->stop_charpos >= BEGV
+ && it->stop_charpos <= it->end_charpos));
it->current.overlay_string_index = -1;
- SET_TEXT_POS (it->current.string_pos, -1, -1);
it->n_overlay_strings = 0;
- it->method = GET_FROM_BUFFER;
/* If we're at the end of the buffer, record that we have
processed the overlay strings there already, so that
least one overlay string was found. */
static int
-get_overlay_strings (it, charpos)
+get_overlay_strings_1 (it, charpos, compute_stop_p)
struct it *it;
int charpos;
{
/* Make sure we know settings in current_buffer, so that we can
restore meaningful values when we're done with the overlay
strings. */
- compute_stop_pos (it);
+ if (compute_stop_p)
+ compute_stop_pos (it);
xassert (it->face_id >= 0);
/* Save IT's settings. They are restored after all overlay
strings have been processed. */
- xassert (it->sp == 0);
+ xassert (!compute_stop_p || it->sp == 0);
push_it (it);
/* Set up IT to deliver display elements from the first overlay
it->end_charpos = SCHARS (it->string);
it->multibyte_p = STRING_MULTIBYTE (it->string);
it->method = GET_FROM_STRING;
+ return 1;
}
- else
- {
- it->string = Qnil;
- it->current.overlay_string_index = -1;
- it->method = GET_FROM_BUFFER;
- }
+
+ it->current.overlay_string_index = -1;
+ return 0;
+}
+
+static int
+get_overlay_strings (it, charpos)
+ struct it *it;
+ int charpos;
+{
+ it->string = Qnil;
+ it->method = GET_FROM_BUFFER;
+
+ (void) get_overlay_strings_1 (it, charpos, 1);
CHECK_IT (it);
{
struct iterator_stack_entry *p;
- xassert (it->sp < 2);
+ xassert (it->sp < IT_STACK_SIZE);
p = it->stack + it->sp;
p->stop_charpos = it->stop_charpos;
xassert (it->face_id >= 0);
p->face_id = it->face_id;
p->string = it->string;
- p->pos = it->current;
+ p->method = it->method;
+ switch (p->method)
+ {
+ case GET_FROM_IMAGE:
+ p->u.image.object = it->object;
+ p->u.image.image_id = it->image_id;
+ p->u.image.slice = it->slice;
+ break;
+ case GET_FROM_COMPOSITION:
+ p->u.comp.object = it->object;
+ p->u.comp.c = it->c;
+ p->u.comp.len = it->len;
+ p->u.comp.cmp_id = it->cmp_id;
+ p->u.comp.cmp_len = it->cmp_len;
+ break;
+ case GET_FROM_STRETCH:
+ p->u.stretch.object = it->object;
+ break;
+ }
+ p->position = it->position;
+ p->current = it->current;
p->end_charpos = it->end_charpos;
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;
p = it->stack + it->sp;
it->stop_charpos = p->stop_charpos;
it->face_id = p->face_id;
+ it->current = p->current;
+ it->position = p->position;
it->string = p->string;
- it->current = p->pos;
+ if (NILP (it->string))
+ SET_TEXT_POS (it->current.string_pos, -1, -1);
+ it->method = p->method;
+ switch (it->method)
+ {
+ case GET_FROM_IMAGE:
+ it->image_id = p->u.image.image_id;
+ it->object = p->u.image.object;
+ it->slice = p->u.image.slice;
+ break;
+ case GET_FROM_COMPOSITION:
+ it->object = p->u.comp.object;
+ it->c = p->u.comp.c;
+ it->len = p->u.comp.len;
+ it->cmp_id = p->u.comp.cmp_id;
+ it->cmp_len = p->u.comp.cmp_len;
+ break;
+ case GET_FROM_STRETCH:
+ it->object = p->u.comp.object;
+ break;
+ }
it->end_charpos = p->end_charpos;
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;
while (IT_CHARPOS (*it) > BEGV)
{
back_to_previous_line_start (it);
+
if (IT_CHARPOS (*it) <= BEGV)
break;
continue;
}
- /* If newline has a display property that replaces the newline with something
- else (image or text), find start of overlay or interval and continue search
- from that point. */
- if (IT_CHARPOS (*it) > BEGV)
- {
- struct it it2 = *it;
- int pos;
- int beg, end;
- Lisp_Object val, overlay;
-
- pos = --IT_CHARPOS (it2);
- --IT_BYTEPOS (it2);
- it2.sp = 0;
- if (handle_display_prop (&it2) == HANDLED_RETURN
- && !NILP (val = get_char_property_and_overlay
- (make_number (pos), Qdisplay, Qnil, &overlay))
- && (OVERLAYP (overlay)
- ? (beg = OVERLAY_POSITION (OVERLAY_START (overlay)))
- : get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil)))
- {
- if (beg < BEGV)
- beg = BEGV;
- IT_CHARPOS (*it) = beg;
- IT_BYTEPOS (*it) = buf_charpos_to_bytepos (current_buffer, beg);
- continue;
- }
- }
+ if (IT_CHARPOS (*it) <= BEGV)
+ break;
- break;
+ {
+ struct it it2;
+ int pos;
+ int beg, end;
+ Lisp_Object val, overlay;
+
+ /* If newline is part of a composition, continue from start of composition */
+ if (find_composition (IT_CHARPOS (*it), -1, &beg, &end, &val, Qnil)
+ && beg < IT_CHARPOS (*it))
+ goto replaced;
+
+ /* If newline is replaced by a display property, find start of overlay
+ or interval and continue search from that point. */
+ it2 = *it;
+ pos = --IT_CHARPOS (it2);
+ --IT_BYTEPOS (it2);
+ it2.sp = 0;
+ if (handle_display_prop (&it2) == HANDLED_RETURN
+ && !NILP (val = get_char_property_and_overlay
+ (make_number (pos), Qdisplay, Qnil, &overlay))
+ && (OVERLAYP (overlay)
+ ? (beg = OVERLAY_POSITION (OVERLAY_START (overlay)))
+ : get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil)))
+ goto replaced;
+
+ /* Newline is not replaced by anything -- so we are done. */
+ break;
+
+ replaced:
+ if (beg < BEGV)
+ beg = BEGV;
+ IT_CHARPOS (*it) = beg;
+ IT_BYTEPOS (*it) = buf_charpos_to_bytepos (current_buffer, beg);
+ }
}
+ it->continuation_lines_width = 0;
+
xassert (IT_CHARPOS (*it) >= BEGV);
xassert (IT_CHARPOS (*it) == BEGV
|| FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
IT_STRING_BYTEPOS (*it) = -1;
it->string = Qnil;
it->method = GET_FROM_BUFFER;
- /* RMS: I added this to fix a bug in move_it_vertically_backward
- where it->area continued to relate to the starting point
- for the backward motion. Bug report from
- Nick Roberts <nick@nick.uklinux.net> on 19 May 2003.
- However, I am not sure whether reseat still does the right thing
- in general after this change. */
+ it->object = it->w->buffer;
it->area = TEXT_AREA;
it->multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
it->sp = 0;
+ it->string_from_display_prop_p = 0;
it->face_before_selective_p = 0;
if (set_stop_p)
display element from the current position of IT. Value is zero if
end of buffer (or C string) is reached. */
+static struct frame *last_escape_glyph_frame = NULL;
+static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS);
+static int last_escape_glyph_merged_face_id = 0;
+
int
get_next_display_element (it)
struct it *it;
face_id = merge_faces (it->f, Qt, lface_id,
it->face_id);
}
+ else if (it->f == last_escape_glyph_frame
+ && it->face_id == last_escape_glyph_face_id)
+ {
+ face_id = last_escape_glyph_merged_face_id;
+ }
else
{
/* Merge the escape-glyph face into the current face. */
face_id = merge_faces (it->f, Qescape_glyph, 0,
it->face_id);
+ last_escape_glyph_frame = it->f;
+ last_escape_glyph_face_id = it->face_id;
+ last_escape_glyph_merged_face_id = face_id;
}
XSETINT (it->ctl_chars[0], g);
face_id = merge_faces (it->f, Qt, lface_id,
it->face_id);
}
+ else if (it->f == last_escape_glyph_frame
+ && it->face_id == last_escape_glyph_face_id)
+ {
+ face_id = last_escape_glyph_merged_face_id;
+ }
else
{
/* Merge the escape-glyph face into the current face. */
face_id = merge_faces (it->f, Qescape_glyph, 0,
it->face_id);
+ last_escape_glyph_frame = it->f;
+ last_escape_glyph_face_id = it->face_id;
+ last_escape_glyph_merged_face_id = face_id;
}
/* Handle soft hyphens in the mode where they only get
case GET_FROM_COMPOSITION:
xassert (it->cmp_id >= 0 && it->cmp_id < n_compositions);
- if (STRINGP (it->string))
+ xassert (it->sp > 0);
+ pop_it (it);
+ if (it->method == GET_FROM_STRING)
{
IT_STRING_BYTEPOS (*it) += it->len;
IT_STRING_CHARPOS (*it) += it->cmp_len;
- it->method = GET_FROM_STRING;
+ it->object = it->string;
goto consider_string_end;
}
- else
+ else if (it->method == GET_FROM_BUFFER)
{
IT_BYTEPOS (*it) += it->len;
IT_CHARPOS (*it) += it->cmp_len;
- it->method = GET_FROM_BUFFER;
+ it->object = it->w->buffer;
}
break;
if (it->dpvec + it->current.dpvec_index == it->dpend)
{
+ int recheck_faces = it->ellipsis_p;
+
if (it->s)
it->method = GET_FROM_C_STRING;
else if (STRINGP (it->string))
it->method = GET_FROM_STRING;
else
- it->method = GET_FROM_BUFFER;
+ {
+ it->method = GET_FROM_BUFFER;
+ it->object = it->w->buffer;
+ }
it->dpvec = NULL;
it->current.dpvec_index = -1;
set_iterator_to_next (it, reseat_p);
}
- /* Recheck faces after display vector */
- it->stop_charpos = IT_CHARPOS (*it);
+ /* Maybe recheck faces after display vector */
+ if (recheck_faces)
+ it->stop_charpos = IT_CHARPOS (*it);
}
break;
&& it->sp > 0)
{
pop_it (it);
- if (STRINGP (it->string))
+ if (it->method == GET_FROM_STRING)
goto consider_string_end;
- it->method = GET_FROM_BUFFER;
}
}
break;
if the `display' property takes up the whole string. */
xassert (it->sp > 0);
pop_it (it);
- it->image_id = 0;
- if (STRINGP (it->string))
- {
- it->method = GET_FROM_STRING;
- goto consider_string_end;
- }
- it->method = GET_FROM_BUFFER;
+ if (it->method == GET_FROM_STRING)
+ goto consider_string_end;
break;
default:
setting face_before_selective_p. */
it->saved_face_id = it->face_id;
it->method = GET_FROM_BUFFER;
+ it->object = it->w->buffer;
reseat_at_next_visible_line_start (it, 1);
it->face_before_selective_p = 1;
}
it->position = (STRINGP (it->string)
? it->current.string_pos
: it->current.pos);
+ if (STRINGP (it->string))
+ it->object = it->string;
+ else
+ it->object = it->w->buffer;
return 1;
}
update_menu_bar (f, 0);
#ifdef HAVE_WINDOW_SYSTEM
update_tool_bar (f, 0);
+#ifdef MAC_OS
+ mac_update_title_bar (f, 0);
+#endif
#endif
UNGCPRO;
}
update_menu_bar (sf, 1);
#ifdef HAVE_WINDOW_SYSTEM
update_tool_bar (sf, 1);
+#ifdef MAC_OS
+ mac_update_title_bar (sf, 1);
+#endif
#endif
}
/* Redisplay the menu bar in case we changed it. */
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
|| defined (USE_GTK)
- if (FRAME_WINDOW_P (f)
-#if defined (MAC_OS)
- /* All frames on Mac OS share the same menubar. So only the
- selected frame should be allowed to set it. */
- && f == SELECTED_FRAME ()
+ if (FRAME_WINDOW_P (f))
+ {
+#ifdef MAC_OS
+ /* All frames on Mac OS share the same menubar. So only
+ the selected frame should be allowed to set it. */
+ if (f == SELECTED_FRAME ())
#endif
- )
- set_frame_menubar (f, 0, 0);
+ set_frame_menubar (f, 0, 0);
+ }
else
/* On a terminal screen, the menu bar is an ordinary screen
line, and this makes it get updated. */
}
-/* Display one line of the tool-bar of frame IT->f. */
+/* Display one line of the tool-bar of frame IT->f.
+
+ HEIGHT specifies the desired height of the tool-bar line.
+ If the actual height of the glyph row is less than HEIGHT, the
+ row's height is increased to HEIGHT, and the icons are centered
+ vertically in the new height.
+
+ If HEIGHT is -1, we are counting needed tool-bar lines, so don't
+ count a final empty row in case the tool-bar width exactly matches
+ the window width.
+*/
static void
-display_tool_bar_line (it)
+display_tool_bar_line (it, height)
struct it *it;
+ int height;
{
struct glyph_row *row = it->glyph_row;
int max_x = it->last_visible_x;
while (it->current_x < max_x)
{
- int x_before, x, n_glyphs_before, i, nglyphs;
+ int x, n_glyphs_before, i, nglyphs;
+ struct it it_before;
/* Get the next display element. */
if (!get_next_display_element (it))
- break;
+ {
+ /* Don't count empty row if we are counting needed tool-bar lines. */
+ if (height < 0 && !it->hpos)
+ return;
+ break;
+ }
/* Produce glyphs. */
- x_before = it->current_x;
- n_glyphs_before = it->glyph_row->used[TEXT_AREA];
+ n_glyphs_before = row->used[TEXT_AREA];
+ it_before = *it;
+
PRODUCE_GLYPHS (it);
- nglyphs = it->glyph_row->used[TEXT_AREA] - n_glyphs_before;
+ nglyphs = row->used[TEXT_AREA] - n_glyphs_before;
i = 0;
- x = x_before;
+ x = it_before.current_x;
while (i < nglyphs)
{
struct glyph *glyph = row->glyphs[TEXT_AREA] + n_glyphs_before + i;
if (x + glyph->pixel_width > max_x)
{
- /* Glyph doesn't fit on line. */
- it->glyph_row->used[TEXT_AREA] = n_glyphs_before + i;
- it->current_x = x;
+ /* Glyph doesn't fit on line. Backtrack. */
+ row->used[TEXT_AREA] = n_glyphs_before;
+ *it = it_before;
+ /* If this is the only glyph on this line, it will never fit on the
+ toolbar, so skip it. But ensure there is at least one glyph,
+ so we don't accidentally disable the tool-bar. */
+ if (n_glyphs_before == 0
+ && (it->vpos > 0 || IT_STRING_CHARPOS (*it) < it->end_charpos-1))
+ break;
goto out;
}
out:;
row->displays_text_p = row->used[TEXT_AREA] != 0;
+ /* Use default face for the border below the tool bar. */
+ if (!row->displays_text_p)
+ it->face_id = DEFAULT_FACE_ID;
extend_face_to_end_of_line (it);
last = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA] - 1;
last->right_box_line_p = 1;
if (last == row->glyphs[TEXT_AREA])
last->left_box_line_p = 1;
+
+ /* Make line the desired height and center it vertically. */
+ if ((height -= it->max_ascent + it->max_descent) > 0)
+ {
+ /* Don't add more than one line height. */
+ height %= FRAME_LINE_HEIGHT (it->f);
+ it->max_ascent += height / 2;
+ it->max_descent += (height + 1) / 2;
+ }
+
compute_line_metrics (it);
/* If line is empty, make it occupy the rest of the tool-bar. */
}
+/* Max tool-bar height. */
+
+#define MAX_FRAME_TOOL_BAR_HEIGHT(f) \
+ ((FRAME_LINE_HEIGHT (f) * FRAME_LINES (f)))
+
/* Value is the number of screen lines needed to make all tool-bar
- items of frame F visible. */
+ items of frame F visible. The number of actual rows needed is
+ returned in *N_ROWS if non-NULL. */
static int
-tool_bar_lines_needed (f)
+tool_bar_lines_needed (f, n_rows)
struct frame *f;
+ int *n_rows;
{
struct window *w = XWINDOW (f->tool_bar_window);
struct it it;
+ /* tool_bar_lines_needed is called from redisplay_tool_bar after building
+ the desired matrix, so use (unused) mode-line row as temporary row to
+ avoid destroying the first tool-bar row. */
+ struct glyph_row *temp_row = MATRIX_MODE_LINE_ROW (w->desired_matrix);
/* Initialize an iterator for iteration over
F->desired_tool_bar_string in the tool-bar window of frame F. */
- init_iterator (&it, w, -1, -1, w->desired_matrix->rows, TOOL_BAR_FACE_ID);
+ init_iterator (&it, w, -1, -1, temp_row, TOOL_BAR_FACE_ID);
it.first_visible_x = 0;
it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
while (!ITERATOR_AT_END_P (&it))
{
- it.glyph_row = w->desired_matrix->rows;
- clear_glyph_row (it.glyph_row);
- display_tool_bar_line (&it);
+ clear_glyph_row (temp_row);
+ it.glyph_row = temp_row;
+ display_tool_bar_line (&it, -1);
}
+ clear_glyph_row (temp_row);
+
+ /* f->n_tool_bar_rows == 0 means "unknown"; -1 means no tool-bar. */
+ if (n_rows)
+ *n_rows = it.vpos > 0 ? it.vpos : -1;
return (it.current_y + FRAME_LINE_HEIGHT (f) - 1) / FRAME_LINE_HEIGHT (f);
}
if (f->n_tool_bar_items)
{
build_desired_tool_bar_string (f);
- nlines = tool_bar_lines_needed (f);
+ nlines = tool_bar_lines_needed (f, NULL);
}
}
build_desired_tool_bar_string (f);
reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
+ if (f->n_tool_bar_rows == 0)
+ {
+ int nlines;
+
+ if ((nlines = tool_bar_lines_needed (f, &f->n_tool_bar_rows),
+ nlines != WINDOW_TOTAL_LINES (w)))
+ {
+ extern Lisp_Object Qtool_bar_lines;
+ Lisp_Object frame;
+ int old_height = WINDOW_TOTAL_LINES (w);
+
+ XSETFRAME (frame, f);
+ Fmodify_frame_parameters (frame,
+ Fcons (Fcons (Qtool_bar_lines,
+ make_number (nlines)),
+ Qnil));
+ if (WINDOW_TOTAL_LINES (w) != old_height)
+ {
+ clear_glyph_matrix (w->desired_matrix);
+ fonts_changed_p = 1;
+ return 1;
+ }
+ }
+ }
+
/* Display as many lines as needed to display all tool-bar items. */
- while (it.current_y < it.last_visible_y)
- display_tool_bar_line (&it);
+
+ if (f->n_tool_bar_rows > 0)
+ {
+ int border, rows, height, extra;
+
+ if (INTEGERP (Vtool_bar_border))
+ border = XINT (Vtool_bar_border);
+ else if (EQ (Vtool_bar_border, Qinternal_border_width))
+ border = FRAME_INTERNAL_BORDER_WIDTH (f);
+ else if (EQ (Vtool_bar_border, Qborder_width))
+ border = f->border_width;
+ else
+ border = 0;
+ if (border < 0)
+ border = 0;
+
+ rows = f->n_tool_bar_rows;
+ height = max (1, (it.last_visible_y - border) / rows);
+ extra = it.last_visible_y - border - height * rows;
+
+ while (it.current_y < it.last_visible_y)
+ {
+ int h = 0;
+ if (extra > 0 && rows-- > 0)
+ {
+ h = (extra + rows - 1) / rows;
+ extra -= h;
+ }
+ display_tool_bar_line (&it, height + h);
+ }
+ }
+ else
+ {
+ while (it.current_y < it.last_visible_y)
+ display_tool_bar_line (&it, 0);
+ }
/* It doesn't make much sense to try scrolling in the tool-bar
window, so don't do it. */
if (auto_resize_tool_bars_p)
{
- int nlines;
+ int nlines, nrows;
+ int max_tool_bar_height = MAX_FRAME_TOOL_BAR_HEIGHT (f);
/* If we couldn't display everything, change the tool-bar's
- height. */
- if (IT_STRING_CHARPOS (it) < it.end_charpos)
+ height if there is room for more. */
+ if (IT_STRING_CHARPOS (it) < it.end_charpos
+ && it.current_y < max_tool_bar_height)
change_height_p = 1;
+ row = it.glyph_row - 1;
+
/* If there are blank lines at the end, except for a partially
visible blank line at the end that is smaller than
FRAME_LINE_HEIGHT, change the tool-bar's height. */
- row = it.glyph_row - 1;
if (!row->displays_text_p
&& row->height >= FRAME_LINE_HEIGHT (f))
change_height_p = 1;
/* If row displays tool-bar items, but is partially visible,
change the tool-bar's height. */
if (row->displays_text_p
- && MATRIX_ROW_BOTTOM_Y (row) > it.last_visible_y)
+ && MATRIX_ROW_BOTTOM_Y (row) > it.last_visible_y
+ && MATRIX_ROW_BOTTOM_Y (row) < max_tool_bar_height)
change_height_p = 1;
/* Resize windows as needed by changing the `tool-bar-lines'
frame parameter. */
if (change_height_p
- && (nlines = tool_bar_lines_needed (f),
+ && (nlines = tool_bar_lines_needed (f, &nrows),
nlines != WINDOW_TOTAL_LINES (w)))
{
extern Lisp_Object Qtool_bar_lines;
int old_height = WINDOW_TOTAL_LINES (w);
XSETFRAME (frame, f);
- clear_glyph_matrix (w->desired_matrix);
Fmodify_frame_parameters (frame,
Fcons (Fcons (Qtool_bar_lines,
make_number (nlines)),
Qnil));
if (WINDOW_TOTAL_LINES (w) != old_height)
- fonts_changed_p = 1;
+ {
+ clear_glyph_matrix (w->desired_matrix);
+ f->n_tool_bar_rows = nrows;
+ fonts_changed_p = 1;
+ }
}
}
retry:
pause = 0;
reconsider_clip_changes (w, current_buffer);
+ last_escape_glyph_frame = NULL;
+ last_escape_glyph_face_id = (1 << FACE_ID_BITS);
/* If new fonts have been loaded that make a glyph matrix adjustment
necessary, do it. */
/* Set cursor position of W. PT is assumed to be displayed in ROW.
DELTA is the number of bytes by which positions recorded in ROW
- differ from current buffer positions. */
+ differ from current buffer positions.
-void
+ Return 0 if cursor is not on this row. 1 otherwise. */
+
+int
set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
struct window *w;
struct glyph_row *row;
x += glyph->pixel_width;
++glyph;
if (cursor_from_overlay_pos
- && last_pos > cursor_from_overlay_pos)
+ && last_pos >= cursor_from_overlay_pos)
{
cursor_from_overlay_pos = 0;
cursor = 0;
}
else
{
- string_before_pos = last_pos;
- string_start = glyph;
- string_start_x = x;
+ if (string_start == NULL)
+ {
+ string_before_pos = last_pos;
+ string_start = glyph;
+ string_start_x = x;
+ }
/* Skip all glyphs from string. */
do
{
+ Lisp_Object cprop;
int pos;
if ((cursor == NULL || glyph > cursor)
- && !NILP (Fget_char_property (make_number ((glyph)->charpos),
- Qcursor, (glyph)->object))
+ && (cprop = Fget_char_property (make_number ((glyph)->charpos),
+ Qcursor, (glyph)->object),
+ !NILP (cprop))
&& (pos = string_buffer_position (w, glyph->object,
string_before_pos),
(pos == 0 /* From overlay */
Add 1 to last_pos so that if point corresponds to the
glyph right after the overlay, we still use a 'cursor'
property found in that overlay. */
- cursor_from_overlay_pos = pos == 0 ? last_pos+1 : 0;
+ cursor_from_overlay_pos = (pos ? 0 : last_pos
+ + (INTEGERP (cprop) ? XINT (cprop) : 0));
cursor = glyph;
cursor_x = x;
}
x += glyph->pixel_width;
++glyph;
}
- while (glyph < end && STRINGP (glyph->object));
+ while (glyph < end && EQ (glyph->object, string_start->object));
}
}
glyph on point by scanning from string_start again. */
Lisp_Object limit;
Lisp_Object string;
+ struct glyph *stop = glyph;
int pos;
limit = make_number (pt_old + 1);
- end = glyph;
glyph = string_start;
x = string_start_x;
string = glyph->object;
pos = string_buffer_position (w, string, string_before_pos);
/* If STRING is from overlay, LAST_POS == 0. We skip such glyphs
because we always put cursor after overlay strings. */
- while (pos == 0 && glyph < end)
+ while (pos == 0 && glyph < stop)
{
string = glyph->object;
- SKIP_GLYPHS (glyph, end, x, EQ (glyph->object, string));
- if (glyph < end)
+ SKIP_GLYPHS (glyph, stop, x, EQ (glyph->object, string));
+ if (glyph < stop)
pos = string_buffer_position (w, glyph->object, string_before_pos);
}
- while (glyph < end)
+ while (glyph < stop)
{
pos = XINT (Fnext_single_char_property_change
(make_number (pos), Qdisplay, Qnil, limit));
break;
/* Skip glyphs from the same string. */
string = glyph->object;
- SKIP_GLYPHS (glyph, end, x, EQ (glyph->object, string));
+ SKIP_GLYPHS (glyph, stop, x, EQ (glyph->object, string));
/* Skip glyphs from an overlay. */
- while (glyph < end
+ while (glyph < stop
&& ! string_buffer_position (w, glyph->object, pos))
{
string = glyph->object;
- SKIP_GLYPHS (glyph, end, x, EQ (glyph->object, string));
+ SKIP_GLYPHS (glyph, stop, x, EQ (glyph->object, string));
}
}
+
+ /* If we reached the end of the line, and end was from a string,
+ cursor is not on this line. */
+ if (glyph == end && row->continued_p)
+ return 0;
}
w->cursor.hpos = glyph - row->glyphs[TEXT_AREA];
else
CHARPOS (this_line_start_pos) = 0;
}
+
+ return 1;
}
rc = CURSOR_MOVEMENT_MUST_SCROLL;
else
{
- set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
- rc = CURSOR_MOVEMENT_SUCCESS;
+ do
+ {
+ if (set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0))
+ {
+ rc = CURSOR_MOVEMENT_SUCCESS;
+ break;
+ }
+ ++row;
+ }
+ while (MATRIX_ROW_BOTTOM_Y (row) < last_y
+ && MATRIX_ROW_START_CHARPOS (row) == PT
+ && cursor_row_p (w, row));
}
}
}
/* IT may overshoot PT if text at PT is invisible. */
else if (IT_CHARPOS (it) > PT && CHARPOS (startp) <= PT)
w->force_start = Qt;
-
-
}
/* Handle case where place to start displaying has been specified,
|| (XFASTINT (w->last_modified) >= MODIFF
&& XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)))
{
+
+ /* If first window line is a continuation line, and window start
+ is inside the modified region, but the first change is before
+ current window start, we must select a new window start.*/
+ if (NILP (w->start_at_line_beg)
+ && CHARPOS (startp) > BEGV)
+ {
+ /* Make sure beg_unchanged and end_unchanged are up to date.
+ Do it only if buffer has really changed. This may or may
+ not have been done by try_window_id (see which) already. */
+ if (MODIFF > SAVE_MODIFF
+ /* This seems to happen sometimes after saving a buffer. */
+ || BEG_UNCHANGED + END_UNCHANGED > Z_BYTE)
+ {
+ if (GPT - BEG < BEG_UNCHANGED)
+ BEG_UNCHANGED = GPT - BEG;
+ if (Z - GPT < END_UNCHANGED)
+ END_UNCHANGED = Z - GPT;
+ }
+
+ if (CHARPOS (startp) > BEG + BEG_UNCHANGED
+ && CHARPOS (startp) <= Z - END_UNCHANGED)
+ {
+ /* There doesn't seems to be a simple way to find a new
+ window start that is near the old window start, so
+ we just recenter. */
+ goto recenter;
+ }
+ }
+
#if GLYPH_DEBUG
debug_method_add (w, "same window start");
#endif
glyph->left_box_line_p,
glyph->right_box_line_p);
}
+ else if (glyph->type == COMPOSITE_GLYPH)
+ {
+ fprintf (stderr,
+ " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+ glyph - row->glyphs[TEXT_AREA],
+ '+',
+ glyph->charpos,
+ (BUFFERP (glyph->object)
+ ? 'B'
+ : (STRINGP (glyph->object)
+ ? 'S'
+ : '-')),
+ glyph->pixel_width,
+ glyph->u.cmp_id,
+ '.',
+ glyph->face_id,
+ glyph->left_box_line_p,
+ glyph->right_box_line_p);
+ }
}
{
if (glyphs != 1)
{
- fprintf (stderr, "Row Start End Used oEI><\\CTZFesm X Y W H V A P\n");
+ fprintf (stderr, "Row Start End Used oE><\\CTZFesm X Y W H V A P\n");
fprintf (stderr, "======================================================================\n");
fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d\
face = FACE_FROM_ID (f, it->face_id);
if (FRAME_WINDOW_P (f)
+ && it->glyph_row->displays_text_p
&& face->box == FACE_NO_BOX
&& face->background == FRAME_BACKGROUND_PIXEL (f)
&& !face->stipple)
{
int bytepos = last_offset;
int charpos = string_byte_to_char (elt, bytepos);
+
+ if (precision <= 0)
+ nchars = string_byte_to_char (elt, offset) - charpos;
n += display_string (NULL, elt, Qnil, 0, charpos,
- it, 0, prec, 0,
+ it, 0, nchars, 0,
STRING_MULTIBYTE (elt));
}
break;
display them, and < 0 means obey the current buffer's value of
enable_multibyte_characters.
- Value is the number of glyphs produced. */
+ Value is the number of columns displayed. */
static int
display_string (string, lisp_string, face_string, face_string_pos,
sure to use a face suitable for unibyte. */
STORE_XCHAR2B (char2b, 0, glyph->u.ch);
}
- else if (glyph->u.ch < 128
- && glyph->face_id < BASIC_FACE_ID_SENTINEL)
+ else if (glyph->u.ch < 128)
{
/* Case of ASCII in a face known to fit ASCII. */
STORE_XCHAR2B (char2b, 0, glyph->u.ch);
s->font = s->face->font;
s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
s->width = glyph->pixel_width;
+ s->nchars = 1;
voffset = glyph->voffset;
for (++glyph;
face_id = FACE_FOR_CHAR (f, face, c);
face = FACE_FROM_ID (f, face_id);
}
- else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
+ else if (c < 128)
{
/* Case of ASCII in a face known to fit ASCII. */
STORE_XCHAR2B (char2b, 0, c);
else
ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font);
+ if (width > 0 && !it->truncate_lines_p
+ && it->current_x + width > it->last_visible_x)
+ width = it->last_visible_x - it->current_x - 1;
+
if (width > 0 && height > 0 && it->glyph_row)
{
Lisp_Object object = it->stack[it->sp - 1].string;
it->descent = it->phys_descent = height - it->ascent;
it->nglyphs = width > 0 && height > 0 ? 1 : 0;
- if (width > 0 && height > 0 && face->box != FACE_NO_BOX)
- {
- if (face->box_line_width > 0)
- {
- it->ascent += face->box_line_width;
- it->descent += face->box_line_width;
- }
-
- if (it->start_of_box_run_p)
- it->pixel_width += abs (face->box_line_width);
- if (it->end_of_box_run_p)
- it->pixel_width += abs (face->box_line_width);
- }
-
take_vertical_position_into_account (it);
}
/* RIF:
Produce glyphs/get display metrics for the display element IT is
- loaded with. See the description of struct display_iterator in
- dispextern.h for an overview of struct display_iterator. */
+ loaded with. See the description of struct it in dispextern.h
+ for an overview of struct it. */
void
x_produce_glyphs (it)
}
else
return get_specified_cursor_type (b->cursor_type, width);
-
- *active_cursor = 0;
- non_selected = 1;
}
+
+ *active_cursor = 0;
+ non_selected = 1;
}
/* Nonselected window or nonselected frame. */
/* Maybe clear the display under the cursor. */
if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
{
- int x, y;
+ int x, y, left_x;
int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
int width;
if (cursor_glyph == NULL)
goto mark_cursor_off;
- x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
+ width = cursor_glyph->pixel_width;
+ left_x = window_box_left_offset (w, TEXT_AREA);
+ x = w->phys_cursor.x;
+ if (x < left_x)
+ width -= left_x - x;
+ width = min (width, window_box_width (w, TEXT_AREA) - x);
y = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, cursor_row->y));
- width = min (cursor_glyph->pixel_width,
- window_box_width (w, TEXT_AREA) - w->phys_cursor.x);
+ x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, max (x, left_x));
+ if (width > 0)
rif->clear_frame_area (f, x, y, width, cursor_row->visible_height);
}
}
if (part == ON_VERTICAL_BORDER)
- cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
+ {
+ cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
+ help_echo_string = build_string ("drag-mouse-1: resize");
+ }
else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE
|| part == ON_SCROLL_BAR)
cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
doc: /* *Non-nil means to scroll (recenter) cursor line if it is not fully visible. */);
make_cursor_line_fully_visible_p = 1;
+ DEFVAR_LISP ("tool-bar-border", &Vtool_bar_border,
+ doc: /* *Border below tool-bar in pixels.
+If an integer, use it as the height of the border.
+If it is one of `internal-border-width' or `border-width', use the
+value of the corresponding frame parameter.
+Otherwise, no border is added below the tool-bar. */);
+ Vtool_bar_border = Qinternal_border_width;
+
DEFVAR_LISP ("tool-bar-button-margin", &Vtool_bar_button_margin,
doc: /* *Margin around tool-bar buttons in pixels.
If an integer, use that for both horizontal and vertical margins.
DEFVAR_LISP ("hscroll-step", &Vhscroll_step,
doc: /* *How many columns to scroll the window when point gets too close to the edge.
-When point is less than `automatic-hscroll-margin' columns from the window
+When point is less than `hscroll-margin' columns from the window
edge, automatic hscrolling will scroll the window by the amount of columns
determined by this variable. If its value is a positive integer, scroll that
many columns. If it's a positive floating-point number, it specifies the