/* 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, 2006, 2007 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
This file is part of GNU Emacs.
Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
+Lisp_Object Qwindow_text_change_functions, Vwindow_text_change_functions;
Lisp_Object Qredisplay_end_trigger_functions, Vredisplay_end_trigger_functions;
Lisp_Object Qinhibit_point_motion_hooks;
Lisp_Object QCeval, QCfile, QCdata, QCpropertize;
point visible. */
int automatic_hscrolling_p;
+Lisp_Object Qauto_hscroll_mode;
/* How close to the margin can point get before the window is scrolled
horizontally. */
static int display_mode_line P_ ((struct window *, enum face_id, Lisp_Object));
static int display_mode_element P_ ((struct it *, int, int, int, Lisp_Object, Lisp_Object, int));
static int store_mode_line_string P_ ((char *, Lisp_Object, int, int, int, Lisp_Object));
-static char *decode_mode_spec P_ ((struct window *, int, int, int, int *));
+static char *decode_mode_spec P_ ((struct window *, int, int, int, int *,
+ Lisp_Object *));
static void display_menu_bar P_ ((struct window *));
static int display_count_lines P_ ((int, int, int, int, int *));
static int display_string P_ ((unsigned char *, Lisp_Object, Lisp_Object,
visible_p = 1;
if (visible_p)
{
+ Lisp_Object window, prop;
+
+ XSETWINDOW (window, w);
+ prop = Fget_char_property (make_number (it.position.charpos),
+ Qinvisible, window);
+
+ /* If charpos coincides with invisible text covered with an
+ ellipsis, use the first glyph of the ellipsis to compute
+ the pixel positions. */
+ if (TEXT_PROP_MEANS_INVISIBLE (prop) == 2)
+ {
+ struct glyph_row *row = it.glyph_row;
+ struct glyph *glyph = row->glyphs[TEXT_AREA];
+ struct glyph *end = glyph + row->used[TEXT_AREA];
+ int x = row->x;
+
+ for (; glyph < end && glyph->charpos < charpos; glyph++)
+ x += glyph->pixel_width;
+
+ top_x = x;
+ }
+
*x = top_x;
*y = max (top_y + max (0, it.max_ascent - it.ascent), window_top_y);
*rtop = max (0, window_top_y - top_y);
XSETWINDOW (it->window, w);
it->w = w;
it->f = XFRAME (w->frame);
-
+
/* Extra space between lines (on window systems only). */
if (base_face_id == DEFAULT_FACE_ID
&& FRAME_WINDOW_P (it->f))
int pos;
{
int noverlays;
- int endpos;
+ EMACS_INT endpos;
Lisp_Object *overlays;
int i;
if (STRINGP (it->string))
{
+ unsigned char *s;
+
pos = IT_STRING_CHARPOS (*it);
pos_byte = IT_STRING_BYTEPOS (*it);
string = it->string;
+ s = SDATA (string) + pos_byte;
+ it->c = STRING_CHAR (s, 0);
}
else
{
pos = IT_CHARPOS (*it);
pos_byte = IT_BYTEPOS (*it);
string = Qnil;
+ it->c = FETCH_CHAR (pos_byte);
}
/* If there's a valid composition and point is not inside of the
Lisp_Object lgstring = AREF (XHASH_TABLE (composition_hash_table)
->key_and_value,
cmp->hash_index * 2);
-
- it->c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 0));
}
else
#endif /* USE_FONT_BACKEND */
int pos = (it->s ? -1
: STRINGP (it->string) ? IT_STRING_CHARPOS (*it)
: IT_CHARPOS (*it));
-
+
it->face_id = FACE_FOR_CHAR (it->f, face, it->c, pos, it->string);
}
struct window *w;
{
int i = 0;
- Lisp_Object vector;
+ Lisp_Object vector, tmp;
/* Reduce consing by keeping one vector in
Vwith_echo_area_save_vector. */
if (NILP (vector))
vector = Fmake_vector (make_number (7), Qnil);
- XSETBUFFER (AREF (vector, i), current_buffer); ++i;
- AREF (vector, i) = Vdeactivate_mark, ++i;
- AREF (vector, i) = make_number (windows_or_buffers_changed), ++i;
+ XSETBUFFER (tmp, current_buffer); ASET (vector, i, tmp); ++i;
+ ASET (vector, i, Vdeactivate_mark); ++i;
+ ASET (vector, i, make_number (windows_or_buffers_changed)); ++i;
if (w)
{
- XSETWINDOW (AREF (vector, i), w); ++i;
- AREF (vector, i) = w->buffer; ++i;
- AREF (vector, i) = make_number (XMARKER (w->pointm)->charpos); ++i;
- AREF (vector, i) = make_number (XMARKER (w->pointm)->bytepos); ++i;
+ XSETWINDOW (tmp, w); ASET (vector, i, tmp); ++i;
+ ASET (vector, i, w->buffer); ++i;
+ ASET (vector, i, make_number (XMARKER (w->pointm)->charpos)); ++i;
+ ASET (vector, i, make_number (XMARKER (w->pointm)->bytepos)); ++i;
}
else
{
int end = i + 4;
for (; i < end; ++i)
- AREF (vector, i) = Qnil;
+ ASET (vector, i, Qnil);
}
xassert (i == ASIZE (vector));
}
-/* Resize mini-window W to fit the size of its contents. EXACT:P
+/* Resize mini-window W to fit the size of its contents. EXACT_P
means size the window exactly to the size needed. Otherwise, it's
only enlarged until W's buffer is empty.
{
Lisp_Object tail, frame;
int changed_count = 0;
-
+
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
-
+
if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f))
{
if (f->resized_p)
f->resized_p = 0;
}
}
-
+
frame_garbaged = 0;
if (changed_count)
++windows_or_buffers_changed;
if (!FRAME_VISIBLE_P (f) || !f->glyphs_initialized_p)
return 0;
-/* The terminal frame is used as the first Emacs frame on the Mac OS. */
-#ifndef MAC_OS8
#ifdef HAVE_WINDOW_SYSTEM
/* When Emacs starts, selected_frame may be the initial terminal
frame. If we let this through, a message would be displayed on
if (FRAME_INITIAL_P (XFRAME (selected_frame)))
return 0;
#endif /* HAVE_WINDOW_SYSTEM */
-#endif
/* Redraw garbaged frames. */
if (frame_garbaged)
format_mode_line_unwind_data (obuf, save_proptrans)
struct buffer *obuf;
{
- Lisp_Object vector;
+ Lisp_Object vector, tmp;
/* Reduce consing by keeping one vector in
Vwith_echo_area_save_vector. */
if (NILP (vector))
vector = Fmake_vector (make_number (7), Qnil);
- AREF (vector, 0) = make_number (mode_line_target);
- AREF (vector, 1) = make_number (MODE_LINE_NOPROP_LEN (0));
- AREF (vector, 2) = mode_line_string_list;
- AREF (vector, 3) = (save_proptrans ? mode_line_proptrans_alist : Qt);
- AREF (vector, 4) = mode_line_string_face;
- AREF (vector, 5) = mode_line_string_face_prop;
+ ASET (vector, 0, make_number (mode_line_target));
+ ASET (vector, 1, make_number (MODE_LINE_NOPROP_LEN (0)));
+ ASET (vector, 2, mode_line_string_list);
+ ASET (vector, 3, save_proptrans ? mode_line_proptrans_alist : Qt);
+ ASET (vector, 4, mode_line_string_face);
+ ASET (vector, 5, mode_line_string_face_prop);
if (obuf)
- XSETBUFFER (AREF (vector, 6), obuf);
+ XSETBUFFER (tmp, obuf);
else
- AREF (vector, 6) = Qnil;
+ tmp = Qnil;
+ ASET (vector, 6, tmp);
return vector;
}
if (!NILP (AREF (vector, 6)))
{
set_buffer_internal_1 (XBUFFER (AREF (vector, 6)));
- AREF (vector, 6) = Qnil;
+ ASET (vector, 6, Qnil);
}
Vmode_line_unwind_vector = vector;
/* Scroll when cursor is inside this scroll margin. */
h_margin = hscroll_margin * WINDOW_FRAME_COLUMN_WIDTH (w);
- if ((XFASTINT (w->hscroll)
- && w->cursor.x <= h_margin)
- || (cursor_row->enabled_p
- && cursor_row->truncated_on_right_p
- && (w->cursor.x >= text_area_width - h_margin)))
+ if (!NILP (Fbuffer_local_value (Qauto_hscroll_mode, w->buffer))
+ && ((XFASTINT (w->hscroll)
+ && w->cursor.x <= h_margin)
+ || (cursor_row->enabled_p
+ && cursor_row->truncated_on_right_p
+ && (w->cursor.x >= text_area_width - h_margin))))
{
struct it it;
int hscroll;
hscroll_windows (window)
Lisp_Object window;
{
- int hscrolled_p;
-
- if (automatic_hscrolling_p)
- {
- hscrolled_p = hscroll_window_tree (window);
- if (hscrolled_p)
- clear_desired_matrices (XFRAME (WINDOW_FRAME (XWINDOW (window))));
- }
- else
- hscrolled_p = 0;
+ int hscrolled_p = hscroll_window_tree (window);
+ if (hscrolled_p)
+ clear_desired_matrices (XFRAME (WINDOW_FRAME (XWINDOW (window))));
return hscrolled_p;
}
selected_frame = frame;
- for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail))
- if (CONSP (XCAR (tail))
- && (sym = XCAR (XCAR (tail)),
- SYMBOLP (sym))
- && (sym = indirect_variable (sym),
- val = SYMBOL_VALUE (sym),
- (BUFFER_LOCAL_VALUEP (val)))
- && XBUFFER_LOCAL_VALUE (val)->check_frame)
- /* Use find_symbol_value rather than Fsymbol_value
- to avoid an error if it is void. */
- find_symbol_value (sym);
-
- for (tail = XFRAME (old)->param_alist; CONSP (tail); tail = XCDR (tail))
- if (CONSP (XCAR (tail))
- && (sym = XCAR (XCAR (tail)),
- SYMBOLP (sym))
- && (sym = indirect_variable (sym),
- val = SYMBOL_VALUE (sym),
- (BUFFER_LOCAL_VALUEP (val)))
- && XBUFFER_LOCAL_VALUE (val)->check_frame)
- find_symbol_value (sym);
+ do
+ {
+ for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail))
+ if (CONSP (XCAR (tail))
+ && (sym = XCAR (XCAR (tail)),
+ SYMBOLP (sym))
+ && (sym = indirect_variable (sym),
+ val = SYMBOL_VALUE (sym),
+ (BUFFER_LOCAL_VALUEP (val)))
+ && XBUFFER_LOCAL_VALUE (val)->check_frame)
+ /* Use find_symbol_value rather than Fsymbol_value
+ to avoid an error if it is void. */
+ find_symbol_value (sym);
+ } while (!EQ (frame, old) && (frame = old, 1));
}
}
}
-
+
/* Notice any pending interrupt request to change frame size. */
do_pending_window_change (1);
#ifdef HAVE_WINDOW_SYSTEM
if (clear_image_cache_count > CLEAR_IMAGE_CACHE_COUNT)
{
- Lisp_Object tail, frame;
- FOR_EACH_FRAME (tail, frame)
- {
- struct frame *f = XFRAME (frame);
- if (FRAME_WINDOW_P (f))
- clear_image_cache (f, 0);
- }
+ clear_image_caches (Qnil);
clear_image_cache_count = 0;
}
#endif /* HAVE_WINDOW_SYSTEM */
*w->desired_matrix->method = 0;
#endif
- specbind (Qinhibit_point_motion_hooks, Qt);
-
+ restart:
reconsider_clip_changes (w, buffer);
/* Has the mode line to be updated? */
/* Really select the buffer, for the sake of buffer-local
variables. */
set_buffer_internal_1 (XBUFFER (w->buffer));
- SET_TEXT_POS (opoint, PT, PT_BYTE);
-
- beg_unchanged = BEG_UNCHANGED;
- end_unchanged = END_UNCHANGED;
current_matrix_up_to_date_p
= (!NILP (w->window_end_valid)
&& XFASTINT (w->last_modified) >= MODIFF
&& XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF);
+ /* Run the window-bottom-change-functions
+ if it is possible that the text on the screen has changed
+ (either due to modification of the text, or any other reason). */
+ if (!current_matrix_up_to_date_p
+ && !NILP (Vwindow_text_change_functions))
+ {
+ safe_run_hooks (Qwindow_text_change_functions);
+ goto restart;
+ }
+
+ beg_unchanged = BEG_UNCHANGED;
+ end_unchanged = END_UNCHANGED;
+
+ SET_TEXT_POS (opoint, PT, PT_BYTE);
+
+ specbind (Qinhibit_point_motion_hooks, Qt);
+
buffer_unchanged_p
= (!NILP (w->window_end_valid)
&& !current_buffer->clip_changed
/* Display must not have been paused, otherwise the current matrix
is not up to date. */
- if (NILP (w->window_end_valid))
- abort ();
+ eassert (!NILP (w->window_end_valid));
/* A value of window_end_pos >= END_UNCHANGED means that the window
end is in the range of changed text. If so, there is no
}
}
- if (row_found && !MATRIX_ROW_DISPLAYS_TEXT_P (row_found))
- abort ();
+ eassert (!row_found || MATRIX_ROW_DISPLAYS_TEXT_P (row_found));
return row_found;
}
break;
/* Remember where item was displayed. */
- AREF (items, i + 3) = make_number (it.hpos);
+ ASET (items, i + 3, make_number (it.hpos));
/* Display the item, pad with one space. */
if (it.current_x < it.last_visible_x)
int multibyte;
int bytepos, charpos;
unsigned char *spec;
+ Lisp_Object string;
bytepos = percent_position;
charpos = (STRING_MULTIBYTE (elt)
? string_byte_to_char (elt, bytepos)
: bytepos);
-
- spec
- = decode_mode_spec (it->w, c, field, prec, &multibyte);
+ spec = decode_mode_spec (it->w, c, field, prec, &multibyte,
+ &string);
switch (mode_line_target)
{
break;
case MODE_LINE_STRING:
{
- int len = strlen (spec);
- Lisp_Object tem = make_string (spec, len);
+ if (NILP (string))
+ {
+ int len = strlen (spec);
+ string = make_string (spec, len);
+ }
props = Ftext_properties_at (make_number (charpos), elt);
/* Should only keep face property in props */
- n += store_mode_line_string (NULL, tem, 0, field, prec, props);
+ n += store_mode_line_string (NULL, string, 0, field, prec, props);
}
break;
case MODE_LINE_DISPLAY:
{
int nglyphs_before, nwritten;
+ if (STRINGP (string))
+ spec = NULL;
nglyphs_before = it->glyph_row->used[TEXT_AREA];
- nwritten = display_string (spec, Qnil, elt,
+ nwritten = display_string (spec, string, elt,
charpos, 0, it,
field, prec, 0,
multibyte);
static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
static char *
-decode_mode_spec (w, c, field_width, precision, multibyte)
+decode_mode_spec (w, c, field_width, precision, multibyte, string)
struct window *w;
register int c;
int field_width, precision;
int *multibyte;
+ Lisp_Object *string;
{
Lisp_Object obj;
struct frame *f = XFRAME (WINDOW_FRAME (w));
char *decode_mode_spec_buf = f->decode_mode_spec_buffer;
struct buffer *b = current_buffer;
- obj = Qnil;
+ *string = obj = Qnil;
*multibyte = 0;
switch (c)
goto no_value;
}
- if (!NILP (w->base_line_number)
- && !NILP (w->base_line_pos)
+ if (INTEGERP (w->base_line_number)
+ && INTEGERP (w->base_line_pos)
&& XFASTINT (w->base_line_pos) <= startpos)
{
line = XFASTINT (w->base_line_number);
if (STRINGP (obj))
{
*multibyte = STRING_MULTIBYTE (obj);
+ *string = obj;
return (char *) SDATA (obj);
}
else
s->cmp->hash_index * 2);
s->face = base_face;
- s->font_info = s->cmp->font;
+ s->font_info = base_face->font_info;
s->font = s->font_info->font;
for (i = 0, s->nchars = 0; i < s->cmp->glyph_len; i++, s->nchars++)
{
if (c != '\t')
{
- int face_id = FACE_FOR_CHAR (s->f, base_face, c, -1, Qnil);
+ int face_id = FACE_FOR_CHAR (s->f, base_face->ascii_face, c,
+ -1, Qnil);
face = get_char_face_and_encoding (s->f, c, face_id,
s->char2b + i, 1, 1);
int n; \
\
char2b = (XChar2b *) alloca ((sizeof *char2b) * cmp->glyph_len); \
- base_face = base_face->ascii_face; \
\
/* Make glyph_strings for each glyph sequence that is drawable by \
the same face, and append them to HEAD/TAIL. */ \
take_vertical_position_into_account (it);
+ if (it->ascent < 0)
+ it->ascent = 0;
+ if (it->descent < 0)
+ it->descent = 0;
+
if (it->glyph_row)
append_glyph (it);
}
#ifdef USE_FONT_BACKEND
if (cmp->method == COMPOSITION_WITH_GLYPH_STRING)
{
- if (! cmp->font || cmp->font != font)
- font_prepare_composition (cmp, it->f);
+ PREPARE_FACE_FOR_DISPLAY (it->f, face);
+ font_prepare_composition (cmp, it->f);
}
else
#endif /* USE_FONT_BACKEND */
+ grefx * (rightmost - leftmost) / 2
- nrefx * width / 2
+ xoff);
-
+
btm = ((grefy == 0 ? highest
: grefy == 1 ? 0
: grefy == 2 ? lowest
it->pixel_width = cmp->pixel_width;
it->ascent = it->phys_ascent = cmp->ascent;
it->descent = it->phys_descent = cmp->descent;
-
if (face->box != FACE_NO_BOX)
{
int thick = face->box_line_width;
it->ascent += overline_margin;
take_vertical_position_into_account (it);
+ if (it->ascent < 0)
+ it->ascent = 0;
+ if (it->descent < 0)
+ it->descent = 0;
if (it->glyph_row)
append_composite_glyph (it);
struct window *w;
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
-
+
/* We could do better, if we knew what type of scroll-bar the adjacent
windows (on either side) have... But we don't :-(
However, I think this works ok. ++KFS 2003-04-25 */
staticpro (&Qwindow_scroll_functions);
Qwindow_scroll_functions = intern ("window-scroll-functions");
+ staticpro (&Qwindow_text_change_functions);
+ Qwindow_text_change_functions = intern ("window-text-change-functions");
+
staticpro (&Qredisplay_end_trigger_functions);
Qredisplay_end_trigger_functions = intern ("redisplay-end-trigger-functions");
is not valid when these functions are called. */);
Vwindow_scroll_functions = Qnil;
+ DEFVAR_LISP ("window-text-change-functions",
+ &Vwindow_text_change_functions,
+ doc: /* Functions to call in redisplay when text in the window might change. */);
+ Vwindow_text_change_functions = Qnil;
+
DEFVAR_LISP ("redisplay-end-trigger-functions", &Vredisplay_end_trigger_functions,
doc: /* Functions called when redisplay of a window reaches the end trigger.
Each function is called with two arguments, the window and the end trigger value.
DEFVAR_BOOL ("auto-hscroll-mode", &automatic_hscrolling_p,
doc: /* *Non-nil means scroll the display automatically to make point visible. */);
automatic_hscrolling_p = 1;
+ Qauto_hscroll_mode = intern ("auto-hscroll-mode");
+ staticpro (&Qauto_hscroll_mode);
DEFVAR_INT ("hscroll-margin", &hscroll_margin,
doc: /* *How many columns away from the window edge point is allowed to get