/* 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.
+ Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995,
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+ 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Emacs.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
/* New redisplay written by Gerd Moellmann <gerd@gnu.org>.
Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
-Lisp_Object Qredisplay_end_trigger_functions;
+Lisp_Object Qredisplay_end_trigger_functions, Vredisplay_end_trigger_functions;
Lisp_Object Qinhibit_point_motion_hooks;
Lisp_Object QCeval, QCfile, QCdata, QCpropertize;
Lisp_Object Qfontified;
Lisp_Object Vfontification_functions;
Lisp_Object Qfontification_functions;
-/* Non-zero means automatically select any window when the mouse
+/* Non-nil means automatically select any window when the mouse
cursor moves into it. */
-int mouse_autoselect_window;
+Lisp_Object Vmouse_autoselect_window;
/* Non-zero means draw tool bar buttons raised when the mouse moves
over them. */
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;
/* Non-nil means escape non-break space and hyphens. */
-Lisp_Object Vshow_nonbreak_escape;
+Lisp_Object Vnobreak_char_display;
#ifdef HAVE_WINDOW_SYSTEM
extern Lisp_Object Voverflow_newline_into_fringe;
Lisp_Object Qescape_glyph;
+/* Name and number of the face used to highlight non-breaking spaces. */
+
+Lisp_Object Qnobreak_space;
+
/* The symbol `image' which is the car of the lists used to represent
images in Lisp. */
Lisp_Object Qmenu_bar_update_hook, Vmenu_bar_update_hook;
-/* Nonzero if overlay arrow has been displayed once in this window. */
+/* Nonzero if an overlay arrow has been displayed in this window. */
static int overlay_arrow_seen;
static Lisp_Object Vmessages_buffer_name;
-/* Current, index 0, and last displayed echo area message. Either
- buffers from echo_buffers, or nil to indicate no message. */
+/* Index 0 is the buffer that holds the current (desired) echo area message,
+ or nil if none is desired right now.
+
+ Index 1 is the buffer that holds the previously displayed echo area message,
+ or nil to indicate no message. This is normally what's on the screen now.
+
+ These two can point to the same buffer. That happens when the last
+ message output by the user (or made by echoing) has been displayed. */
Lisp_Object echo_area_buffer[2];
-/* The buffers referenced from echo_area_buffer. */
+/* Permanent pointers to the two buffers that are used for echo area
+ purposes. Once the two buffers are made, and their pointers are
+ placed here, these two slots remain unchanged unless those buffers
+ need to be created afresh. */
static Lisp_Object echo_buffer[2];
Lisp_Object Qinhibit_menubar_update;
int inhibit_menubar_update;
+/* When evaluating expressions from menu bar items (enable conditions,
+ for instance), this is the frame they are being processed for. */
+
+Lisp_Object Vmenu_updating_frame;
+
/* Maximum height for resizing mini-windows. Either a float
specifying a fraction of the available height, or an integer
specifying a number of lines. */
static int message_cleared_p;
-/* Non-zero means we want a hollow cursor in windows that are not
- selected. Zero means there's no cursor in such windows. */
-
-Lisp_Object Vcursor_in_non_selected_windows;
-Lisp_Object Qcursor_in_non_selected_windows;
-
/* How to blink the default frame cursor off. */
Lisp_Object Vblink_cursor_alist;
struct buffer *displayed_buffer;
+/* Space between overline and text. */
+
+EMACS_INT overline_margin;
+
/* Value returned from text property handlers (see below). */
enum prop_handled
#define CLEAR_FACE_CACHE_COUNT 500
static int clear_face_cache_count;
+/* Similarly for the image cache. */
+
+#ifdef HAVE_WINDOW_SYSTEM
+#define CLEAR_IMAGE_CACHE_COUNT 101
+static int clear_image_cache_count;
+#endif
+
/* Record the previous terminal frame we displayed. */
static struct frame *previous_terminal_frame;
struct text_pos));
static void reconsider_clip_changes P_ ((struct window *, struct buffer *));
static int text_outside_line_unchanged_p P_ ((struct window *, int, int));
-static void store_frame_title_char P_ ((char));
-static int store_frame_title P_ ((const unsigned char *, int, int));
+static void store_mode_line_noprop_char P_ ((char));
+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));
Lisp_Object));
static void extend_face_to_end_of_line P_ ((struct it *));
static int append_space_for_newline P_ ((struct it *, int));
-static int make_cursor_line_fully_visible P_ ((struct window *, int));
+static int cursor_row_fully_visible_p P_ ((struct window *, int, 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));
static Lisp_Object redisplay_window_error ();
static Lisp_Object redisplay_window_0 P_ ((Lisp_Object));
static Lisp_Object redisplay_window_1 P_ ((Lisp_Object));
-static void update_menu_bar P_ ((struct frame *, int));
+static int update_menu_bar P_ ((struct frame *, int, int));
static int try_window_reusing_current_matrix P_ ((struct window *));
static int try_window_id P_ ((struct window *));
static int display_line P_ ((struct it *));
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));
/* Return 1 if position CHARPOS is visible in window W.
+ CHARPOS < 0 means return info about WINDOW_END position.
If visible, set *X and *Y to pixel coordinates of top left corner.
Set *RTOP and *RBOT to pixel height of an invisible area of glyph at POS.
- EXACT_MODE_LINE_HEIGHTS_P non-zero means compute exact mode-line
- and header-lines heights. */
+ Set *ROWH and *VPOS to row's visible height and VPOS (row number). */
int
-pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p)
+pos_visible_p (w, charpos, x, y, rtop, rbot, rowh, vpos)
struct window *w;
- int charpos, *x, *y, *rtop, *rbot, exact_mode_line_heights_p;
+ int charpos, *x, *y, *rtop, *rbot, *rowh, *vpos;
{
struct it it;
struct text_pos top;
SET_TEXT_POS_FROM_MARKER (top, w->start);
- /* Compute exact mode line heights, if requested. */
- if (exact_mode_line_heights_p)
- {
- if (WINDOW_WANTS_MODELINE_P (w))
- current_mode_line_height
- = display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w),
- current_buffer->mode_line_format);
+ /* Compute exact mode line heights. */
+ if (WINDOW_WANTS_MODELINE_P (w))
+ current_mode_line_height
+ = display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w),
+ current_buffer->mode_line_format);
- if (WINDOW_WANTS_HEADER_LINE_P (w))
- current_header_line_height
- = display_mode_line (w, HEADER_LINE_FACE_ID,
+ if (WINDOW_WANTS_HEADER_LINE_P (w))
+ current_header_line_height
+ = display_mode_line (w, HEADER_LINE_FACE_ID,
current_buffer->header_line_format);
- }
start_display (&it, w, top);
- move_it_to (&it, charpos, 0, it.last_visible_y, -1,
- MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+ move_it_to (&it, charpos, -1, it.last_visible_y-1, -1,
+ (charpos >= 0 ? MOVE_TO_POS : 0) | MOVE_TO_Y);
/* Note that we may overshoot because of invisible text. */
- if (IT_CHARPOS (it) >= charpos)
+ if (charpos >= 0 && IT_CHARPOS (it) >= charpos)
{
+ int top_x = it.current_x;
int top_y = it.current_y;
int bottom_y = (last_height = 0, line_bottom_y (&it));
int window_top_y = WINDOW_HEADER_LINE_HEIGHT (w);
visible_p = bottom_y > window_top_y;
else if (top_y < it.last_visible_y)
visible_p = 1;
- if (visible_p && x)
+ if (visible_p)
{
- *x = it.current_x;
+ *x = top_x;
*y = max (top_y + max (0, it.max_ascent - it.ascent), window_top_y);
- if (rtop)
- {
- *rtop = max (0, window_top_y - top_y);
- *rbot = max (0, bottom_y - it.last_visible_y);
- }
+ *rtop = max (0, window_top_y - top_y);
+ *rbot = max (0, bottom_y - it.last_visible_y);
+ *rowh = max (0, (min (bottom_y, it.last_visible_y)
+ - max (top_y, window_top_y)));
+ *vpos = it.vpos;
}
}
- else if (it.current_y + it.max_ascent + it.max_descent > it.last_visible_y)
+ else
{
struct it it2;
it2 = it;
- move_it_by_lines (&it, 1, 0);
+ if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n')
+ move_it_by_lines (&it, 1, 0);
if (charpos < IT_CHARPOS (it))
{
visible_p = 1;
- 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;
- if (rtop)
- {
- *rtop = 0;
- *rbot = max (0, (it2.current_y + it2.max_ascent + it2.max_descent) - it.last_visible_y);
- }
- }
+ move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
+ *x = it2.current_x;
+ *y = it2.current_y + it2.max_ascent - it2.ascent;
+ *rtop = max (0, -it2.current_y);
+ *rbot = max (0, ((it2.current_y + it2.max_ascent + it2.max_descent)
+ - it.last_visible_y));
+ *rowh = max (0, (min (it2.current_y + it2.max_ascent + it2.max_descent,
+ it.last_visible_y)
+ - max (it2.current_y,
+ WINDOW_HEADER_LINE_HEIGHT (w))));
+ *vpos = it2.vpos;
}
}
current_header_line_height = current_mode_line_height = -1;
+ if (visible_p && XFASTINT (w->hscroll) > 0)
+ *x -= XFASTINT (w->hscroll) * WINDOW_FRAME_COLUMN_WIDTH (w);
+
+#if 0
+ /* Debugging code. */
+ if (visible_p)
+ fprintf (stderr, "+pv pt=%d vs=%d --> x=%d y=%d rt=%d rb=%d rh=%d vp=%d\n",
+ charpos, w->vscroll, *x, *y, *rtop, *rbot, *rowh, *vpos);
+ else
+ fprintf (stderr, "-pv pt=%d vs=%d\n", charpos, w->vscroll);
+#endif
+
return visible_p;
}
}
/* EXPORT:
- Return in *R the clipping rectangle for glyph string S. */
+ Return in RECTS[] at most N clipping rectangles for glyph string S.
+ Return the number of stored rectangles. */
-void
-get_glyph_string_clip_rect (s, nr)
+int
+get_glyph_string_clip_rects (s, rects, n)
struct glyph_string *s;
- NativeRectangle *nr;
+ NativeRectangle *rects;
+ int n;
{
XRectangle r;
+ if (n <= 0)
+ return 0;
+
if (s->row->full_width_p)
{
/* Draw full-width. X coordinates are relative to S->w->left_col. */
/* If S draws overlapping rows, it's sufficient to use the top and
bottom of the window for clipping because this glyph string
intentionally draws over other lines. */
- if (s->for_overlaps_p)
+ if (s->for_overlaps)
{
r.y = WINDOW_HEADER_LINE_HEIGHT (s->w);
r.height = window_text_bottom_y (s->w) - r.y;
+
+ /* Alas, the above simple strategy does not work for the
+ environments with anti-aliased text: if the same text is
+ drawn onto the same place multiple times, it gets thicker.
+ If the overlap we are processing is for the erased cursor, we
+ take the intersection with the rectagle of the cursor. */
+ if (s->for_overlaps & OVERLAPS_ERASED_CURSOR)
+ {
+ XRectangle rc, r_save = r;
+
+ rc.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (s->w, s->w->phys_cursor.x);
+ rc.y = s->w->phys_cursor.y;
+ rc.width = s->w->phys_cursor_width;
+ rc.height = s->w->phys_cursor_height;
+
+ x_intersect_rectangles (&r_save, &rc, &r);
+ }
}
else
{
}
}
+ if ((s->for_overlaps & OVERLAPS_BOTH) == 0
+ || ((s->for_overlaps & OVERLAPS_BOTH) == OVERLAPS_BOTH && n == 1))
+ {
#ifdef CONVERT_FROM_XRECT
- CONVERT_FROM_XRECT (r, *nr);
+ CONVERT_FROM_XRECT (r, *rects);
#else
- *nr = r;
+ *rects = r;
+#endif
+ return 1;
+ }
+ else
+ {
+ /* If we are processing overlapping and allowed to return
+ multiple clipping rectangles, we exclude the row of the glyph
+ string from the clipping rectangle. This is to avoid drawing
+ the same text on the environment with anti-aliasing. */
+#ifdef CONVERT_FROM_XRECT
+ XRectangle rs[2];
+#else
+ XRectangle *rs = rects;
+#endif
+ int i = 0, row_y = WINDOW_TO_FRAME_PIXEL_Y (s->w, s->row->y);
+
+ if (s->for_overlaps & OVERLAPS_PRED)
+ {
+ 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;
+ }
+ 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;
+ }
+ i++;
+ }
+
+ n = i;
+#ifdef CONVERT_FROM_XRECT
+ for (i = 0; i < n; i++)
+ CONVERT_FROM_XRECT (rs[i], rects[i]);
#endif
+ return n;
+ }
+}
+
+/* EXPORT:
+ Return in *NR the clipping rectangle for glyph string S. */
+
+void
+get_glyph_string_clip_rect (s, nr)
+ struct glyph_string *s;
+ NativeRectangle *nr;
+{
+ get_glyph_string_clip_rects (s, nr, 1);
}
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 x, y, wd, h, h0, y0;
#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;
+}
+
+/*
+ * Remember which glyph the mouse is over.
+ */
+
+void
+remember_mouse_glyph (f, gx, gy, rect)
+ struct frame *f;
+ int gx, gy;
+ NativeRectangle *rect;
+{
+ Lisp_Object window;
+ struct window *w;
+ struct glyph_row *r, *gr, *end_row;
+ enum window_part part;
+ enum glyph_row_area area;
+ int x, y, width, height;
+
+ /* Try to determine frame pixel position and size of the glyph under
+ frame pixel coordinates X/Y on frame F. */
+
+ window = window_from_coordinates (f, gx, gy, &part, &x, &y, 0);
+ if (NILP (window))
+ {
+ width = FRAME_SMALLEST_CHAR_WIDTH (f);
+ height = FRAME_SMALLEST_FONT_HEIGHT (f);
+ goto virtual_glyph;
+ }
+
+ w = XWINDOW (window);
+ width = WINDOW_FRAME_COLUMN_WIDTH (w);
+ height = WINDOW_FRAME_LINE_HEIGHT (w);
+
+ r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+ end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
+
+ if (w->pseudo_window_p)
+ {
+ area = TEXT_AREA;
+ part = ON_MODE_LINE; /* Don't adjust margin. */
+ goto text_glyph;
+ }
+
+ switch (part)
+ {
+ case ON_LEFT_MARGIN:
+ area = LEFT_MARGIN_AREA;
+ goto text_glyph;
+
+ case ON_RIGHT_MARGIN:
+ area = RIGHT_MARGIN_AREA;
+ goto text_glyph;
+
+ case ON_HEADER_LINE:
+ case ON_MODE_LINE:
+ gr = (part == ON_HEADER_LINE
+ ? MATRIX_HEADER_LINE_ROW (w->current_matrix)
+ : MATRIX_MODE_LINE_ROW (w->current_matrix));
+ gy = gr->y;
+ area = TEXT_AREA;
+ goto text_glyph_row_found;
+
+ case ON_TEXT:
+ area = TEXT_AREA;
+
+ text_glyph:
+ gr = 0; gy = 0;
+ for (; r <= end_row && r->enabled_p; ++r)
+ if (r->y + r->height > y)
+ {
+ gr = r; gy = r->y;
+ break;
+ }
+
+ text_glyph_row_found:
+ if (gr && gy <= y)
+ {
+ struct glyph *g = gr->glyphs[area];
+ struct glyph *end = g + gr->used[area];
+
+ height = gr->height;
+ for (gx = gr->x; g < end; gx += g->pixel_width, ++g)
+ if (gx + g->pixel_width > x)
+ break;
+
+ if (g < end)
+ {
+ if (g->type == IMAGE_GLYPH)
+ {
+ /* Don't remember when mouse is over image, as
+ image may have hot-spots. */
+ STORE_NATIVE_RECT (*rect, 0, 0, 0, 0);
+ return;
+ }
+ width = g->pixel_width;
+ }
+ else
+ {
+ /* Use nominal char spacing at end of line. */
+ x -= gx;
+ gx += (x / width) * width;
+ }
+
+ if (part != ON_MODE_LINE && part != ON_HEADER_LINE)
+ gx += window_box_left_offset (w, area);
+ }
+ else
+ {
+ /* Use nominal line height at end of window. */
+ gx = (x / width) * width;
+ y -= gy;
+ gy += (y / height) * height;
+ }
+ break;
+
+ case ON_LEFT_FRINGE:
+ gx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+ ? WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
+ : window_box_right_offset (w, LEFT_MARGIN_AREA));
+ width = WINDOW_LEFT_FRINGE_WIDTH (w);
+ goto row_glyph;
+
+ case ON_RIGHT_FRINGE:
+ gx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+ ? window_box_right_offset (w, RIGHT_MARGIN_AREA)
+ : window_box_right_offset (w, TEXT_AREA));
+ width = WINDOW_RIGHT_FRINGE_WIDTH (w);
+ goto row_glyph;
+
+ case ON_SCROLL_BAR:
+ gx = (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
+ ? 0
+ : (window_box_right_offset (w, RIGHT_MARGIN_AREA)
+ + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+ ? WINDOW_RIGHT_FRINGE_WIDTH (w)
+ : 0)));
+ width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
+
+ row_glyph:
+ gr = 0, gy = 0;
+ for (; r <= end_row && r->enabled_p; ++r)
+ if (r->y + r->height > y)
+ {
+ gr = r; gy = r->y;
+ break;
+ }
+
+ if (gr && gy <= y)
+ height = gr->height;
+ else
+ {
+ /* Use nominal line height at end of window. */
+ y -= gy;
+ gy += (y / height) * height;
+ }
+ break;
+
+ default:
+ ;
+ virtual_glyph:
+ /* If there is no glyph under the mouse, then we divide the screen
+ into a grid of the smallest glyph in the frame, and use that
+ as our "glyph". */
+
+ /* Arrange for the division in FRAME_PIXEL_X_TO_COL etc. to
+ round down even for negative values. */
+ if (gx < 0)
+ gx -= width - 1;
+ if (gy < 0)
+ gy -= height - 1;
+
+ gx = (gx / width) * width;
+ gy = (gy / height) * height;
+
+ goto store_rect;
+ }
+
+ gx += WINDOW_LEFT_EDGE_X (w);
+ gy += WINDOW_TOP_EDGE_Y (w);
+
+ store_rect:
+ STORE_NATIVE_RECT (*rect, gx, gy, width, height);
+
+ /* Visible feedback for debugging. */
+#if 0
+#if HAVE_X_WINDOWS
+ XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ f->output_data.x->normal_gc,
+ gx, gy, width, height);
+#endif
+#endif
}
init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID);
it->first_vpos = first_vpos;
- if (!it->truncate_lines_p)
+ /* Don't reseat to previous visible line start if current start
+ position is in a string or image. */
+ if (it->method == GET_FROM_BUFFER && !it->truncate_lines_p)
{
int start_at_line_beg_p;
int first_y = it->current_y;
after-string. */
init_iterator (it, w, charpos, bytepos, NULL, DEFAULT_FACE_ID);
- for (i = 0; i < it->n_overlay_strings; ++i)
+ /* This only scans the current chunk -- it should scan all chunks.
+ However, OVERLAY_STRING_CHUNK_SIZE has been increased from 3 in 21.1
+ to 16 in 22.1 to make this a lesser problem. */
+ for (i = 0; i < it->n_overlay_strings && i < OVERLAY_STRING_CHUNK_SIZE; ++i)
{
const char *s = SDATA (it->overlay_strings[i]);
const char *e = s + SBYTES (it->overlay_strings[i]);
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;
}
struct it *it;
{
enum prop_handled handled;
- int handle_overlay_change_p = 1;
+ int handle_overlay_change_p;
struct props *p;
it->dpvec = NULL;
it->current.dpvec_index = -1;
+ handle_overlay_change_p = !it->ignore_overlay_strings_at_pos_p;
+ it->ignore_overlay_strings_at_pos_p = 0;
+
+ /* Use face of preceding text for ellipsis (if invisible) */
+ if (it->selective_display_ellipsis_p)
+ it->saved_face_id = it->face_id;
do
{
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;
}
Lisp_Object prop, pos;
enum prop_handled handled = HANDLED_NORMALLY;
+ if (!NILP (Vmemory_full))
+ return handled;
+
/* Get the value of the `fontified' property at IT's current buffer
position. (The `fontified' property doesn't have a special
meaning in strings.) If the value is nil, call functions from
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->dpvec_face_id = -1;
/* Remember the current face id in case glyphs specify faces.
- IT's face is restored in set_iterator_to_next. */
- it->saved_face_id = it->face_id;
+ IT's face is restored in set_iterator_to_next.
+ saved_face_id was set to preceding char's face in handle_stop. */
+ if (it->saved_face_id < 0 || it->saved_face_id != it->face_id)
+ it->saved_face_id = it->face_id = DEFAULT_FACE_ID;
+
it->method = GET_FROM_DISPLAY_VECTOR;
it->ellipsis_p = 1;
}
}
else
{
- object = it->w->buffer;
+ XSETWINDOW (object, it->w);
position = &it->current.pos;
}
if (NILP (prop))
return HANDLED_NORMALLY;
+ if (!STRINGP (it->string))
+ object = it->w->buffer;
+
if (CONSP (prop)
/* Simple properties. */
&& !EQ (XCAR (prop), Qimage)
}
else
{
- if (handle_single_display_spec (it, prop, object, position, 0))
+ int ret = handle_single_display_spec (it, prop, object, position, 0);
+ if (ret < 0) /* Replaced by "", i.e. nothing. */
+ return HANDLED_RECOMPUTE_PROPS;
+ if (ret)
display_replaced_p = 1;
}
property ends.
Value is non-zero if something was found which replaces the display
- of buffer or string text. */
+ of buffer or string text. Specifically, the value is -1 if that
+ "something" is "nothing". */
static int
handle_single_display_spec (it, spec, object, position,
{
Lisp_Object form;
Lisp_Object location, value;
- struct text_pos start_pos;
+ struct text_pos start_pos, save_pos;
int valid_p;
/* If SPEC is a list of the form `(when FORM . VALUE)', evaluate FORM.
if (CONSP (XCDR (XCDR (spec))))
{
Lisp_Object face_name = XCAR (XCDR (XCDR (spec)));
- int face_id2 = lookup_named_face (it->f, face_name, 'A', 0);
+ int face_id2 = lookup_derived_face (it->f, face_name,
+ 'A', FRINGE_FACE_ID, 0);
if (face_id2 >= 0)
face_id = face_id2;
}
/* Save current settings of IT so that we can restore them
when we are finished with the glyph property value. */
+ save_pos = it->position;
+ it->position = *position;
push_it (it);
+ it->position = save_pos;
it->area = TEXT_AREA;
it->what = IT_IMAGE;
{
/* Save current settings of IT so that we can restore them
when we are finished with the glyph property value. */
+ save_pos = it->position;
+ it->position = *position;
push_it (it);
+ it->position = save_pos;
if (NILP (location))
it->area = TEXT_AREA;
if (STRINGP (value))
{
+ if (SCHARS (value) == 0)
+ {
+ pop_it (it);
+ return -1; /* Replaced by "", i.e. nothing. */
+ }
it->string = value;
it->multibyte_p = STRING_MULTIBYTE (it->string);
it->current.overlay_string_index = -1;
{
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;
+ case GET_FROM_BUFFER:
+ it->object = it->w->buffer;
+ break;
+ case GET_FROM_STRING:
+ it->object = it->string;
+ 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)
+ break;
+
{
- struct it it2 = *it;
- int pos = IT_CHARPOS (*it);
+ 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
&& (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;
- }
+ 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);
}
- break;
}
+ it->continuation_lines_width = 0;
+
xassert (IT_CHARPOS (*it) >= BEGV);
xassert (IT_CHARPOS (*it) == BEGV
|| FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
&& indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
(double) it->selective)) /* iftc */
{
- xassert (FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
+ xassert (IT_BYTEPOS (*it) == BEGV
+ || FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
newline_found_p = forward_to_next_line_start (it, &skipped_p);
}
xassert (CHARPOS (pos) >= BEGV && CHARPOS (pos) <= ZV);
it->current.pos = it->position = pos;
- XSETBUFFER (it->object, current_buffer);
it->end_charpos = ZV;
it->dpvec = NULL;
it->current.dpvec_index = -1;
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;
? ((it->c >= 127
&& it->len == 1)
|| !CHAR_PRINTABLE_P (it->c)
- || (!NILP (Vshow_nonbreak_escape)
- && (it->c == 0x8ad || it->c == 0x8a0)))
+ || (!NILP (Vnobreak_char_display)
+ && (it->c == 0x8a0 || it->c == 0x8ad
+ || it->c == 0x920 || it->c == 0x92d
+ || it->c == 0xe20 || it->c == 0xe2d
+ || it->c == 0xf20 || it->c == 0xf2d)))
: (it->c >= 127
&& (!unibyte_display_via_language_environment
|| it->c == unibyte_char_to_multibyte (it->c)))))
display. Then, set IT->dpvec to these glyphs. */
GLYPH g;
int ctl_len;
- int face_id, lface_id;
+ int face_id, lface_id = 0 ;
GLYPH escape_glyph;
+ /* Handle control characters with ^. */
+
if (it->c < 128 && it->ctl_arrow_p)
{
+ g = '^'; /* default glyph for Control */
/* Set IT->ctl_chars[0] to the glyph for `^'. */
if (it->dp
&& INTEGERP (DISP_CTRL_GLYPH (it->dp))
{
g = XINT (DISP_CTRL_GLYPH (it->dp));
lface_id = FAST_GLYPH_FACE (g);
- if (lface_id)
- {
- g = FAST_GLYPH_CHAR (g);
- face_id = merge_faces (it->f, Qt, lface_id,
- it->face_id);
- }
+ }
+ if (lface_id)
+ {
+ g = FAST_GLYPH_CHAR (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);
- g = '^';
+ 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);
goto display_control;
}
+ /* Handle non-break space in the mode where it only gets
+ highlighting. */
+
+ if (EQ (Vnobreak_char_display, Qt)
+ && (it->c == 0x8a0 || it->c == 0x920
+ || it->c == 0xe20 || it->c == 0xf20))
+ {
+ /* Merge the no-break-space face into the current face. */
+ face_id = merge_faces (it->f, Qnobreak_space, 0,
+ it->face_id);
+
+ g = it->c = ' ';
+ XSETINT (it->ctl_chars[0], g);
+ ctl_len = 1;
+ goto display_control;
+ }
+
+ /* Handle sequences that start with the "escape glyph". */
+
+ /* the default escape glyph is \. */
+ escape_glyph = '\\';
+
if (it->dp
&& INTEGERP (DISP_ESCAPE_GLYPH (it->dp))
&& GLYPH_CHAR_VALID_P (XFASTINT (DISP_ESCAPE_GLYPH (it->dp))))
{
escape_glyph = XFASTINT (DISP_ESCAPE_GLYPH (it->dp));
lface_id = FAST_GLYPH_FACE (escape_glyph);
- if (lface_id)
- {
- escape_glyph = FAST_GLYPH_CHAR (escape_glyph);
- face_id = merge_faces (it->f, Qt, lface_id,
- it->face_id);
- }
+ }
+ if (lface_id)
+ {
+ /* The display table specified a face.
+ Merge it into face_id and also into escape_glyph. */
+ escape_glyph = FAST_GLYPH_CHAR (escape_glyph);
+ 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);
- escape_glyph = '\\';
+ last_escape_glyph_frame = it->f;
+ last_escape_glyph_face_id = it->face_id;
+ last_escape_glyph_merged_face_id = face_id;
}
- if (it->c == 0x8a0 || it->c == 0x8ad)
+ /* Handle soft hyphens in the mode where they only get
+ highlighting. */
+
+ if (EQ (Vnobreak_char_display, Qt)
+ && (it->c == 0x8ad || it->c == 0x92d
+ || it->c == 0xe2d || it->c == 0xf2d))
+ {
+ g = it->c = '-';
+ XSETINT (it->ctl_chars[0], g);
+ ctl_len = 1;
+ goto display_control;
+ }
+
+ /* Handle non-break space and soft hyphen
+ with the escape glyph. */
+
+ if (it->c == 0x8a0 || it->c == 0x8ad
+ || it->c == 0x920 || it->c == 0x92d
+ || it->c == 0xe20 || it->c == 0xe2d
+ || it->c == 0xf20 || it->c == 0xf2d)
{
XSETINT (it->ctl_chars[0], escape_glyph);
- g = it->c == 0x8ad ? '-' : ' ';
+ g = it->c = ((it->c & 0xf) == 0 ? ' ' : '-');
XSETINT (it->ctl_chars[1], g);
ctl_len = 2;
goto display_control;
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;
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;
}
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;
reseat_at_next_visible_line_start (it, 1);
else if (it->dpvec_char_len > 0)
{
+ if (it->method == GET_FROM_STRING
+ && it->n_overlay_strings > 0)
+ it->ignore_overlay_strings_at_pos_p = 1;
it->len = it->dpvec_char_len;
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:
/* Precondition. */
xassert (it->dpvec && it->current.dpvec_index >= 0);
+ it->face_id = it->saved_face_id;
+
if (INTEGERP (*it->dpvec)
&& GLYPH_CHAR_VALID_P (XFASTINT (*it->dpvec)))
{
}
}
- /* Record what we have and where it came from. Note that we store a
- buffer position in IT->position although it could arguably be a
- string position. */
+ /* Record what we have and where it came from. */
it->what = IT_CHARACTER;
it->object = it->string;
it->position = position;
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;
}
Moving an iterator without producing glyphs
***********************************************************************/
+/* Check if iterator is at a position corresponding to a valid buffer
+ position after some move_it_ call. */
+
+#define IT_POS_VALID_AFTER_MOVE_P(it) \
+ ((it)->method == GET_FROM_STRING \
+ ? IT_STRING_CHARPOS (*it) == 0 \
+ : 1)
+
+
/* Move iterator IT to a specified buffer or X position within one
line on the display without producing glyphs.
((op & MOVE_TO_POS) != 0 \
&& BUFFERP (it->object) \
&& IT_CHARPOS (*it) >= to_charpos \
- && (it->method == GET_FROM_BUFFER || \
- (it->method == GET_FROM_DISPLAY_VECTOR && \
- it->dpvec + it->current.dpvec_index + 1 >= it->dpend)))
+ && (it->method == GET_FROM_BUFFER \
+ || (it->method == GET_FROM_DISPLAY_VECTOR \
+ && it->dpvec + it->current.dpvec_index + 1 >= it->dpend)))
while (1)
{
int x, i, ascent = 0, descent = 0;
+ /* Stop if we move beyond TO_CHARPOS (after an image or stretch glyph). */
+ if ((op & MOVE_TO_POS) != 0
+ && BUFFERP (it->object)
+ && it->method == GET_FROM_BUFFER
+ && IT_CHARPOS (*it) > to_charpos)
+ {
+ result = MOVE_POS_MATCH_OR_ZV;
+ break;
+ }
+
/* Stop when ZV reached.
We used to stop here when TO_CHARPOS reached as well, but that is
too soon if this glyph does not fit on this line. So we handle it
glyphs have the same width. */
int single_glyph_width = it->pixel_width / it->nglyphs;
int new_x;
+ int x_before_this_char = x;
+ int hpos_before_this_char = it->hpos;
for (i = 0; i < it->nglyphs; ++i, x = new_x)
{
{
++it->hpos;
it->current_x = new_x;
+
+ /* The character's last glyph just barely fits
+ in this row. */
if (i == it->nglyphs - 1)
{
+ /* If this is the destination position,
+ return a position *before* it in this row,
+ now that we know it fits in this row. */
+ if (BUFFER_POS_REACHED_P ())
+ {
+ it->hpos = hpos_before_this_char;
+ it->current_x = x_before_this_char;
+ result = MOVE_POS_MATCH_OR_ZV;
+ break;
+ }
+
set_iterator_to_next (it, 1);
#ifdef HAVE_WINDOW_SYSTEM
if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
if (reached)
break;
}
+ else if (BUFFERP (it->object)
+ && it->method == GET_FROM_BUFFER
+ && IT_CHARPOS (*it) >= to_charpos)
+ skip = MOVE_POS_MATCH_OR_ZV;
else
skip = move_it_in_display_line_to (it, to_charpos, -1, MOVE_TO_POS);
y-distance. */
it2 = *it;
it2.max_ascent = it2.max_descent = 0;
- move_it_to (&it2, start_pos, -1, -1, it2.vpos + 1,
- MOVE_TO_POS | MOVE_TO_VPOS);
+ do
+ {
+ move_it_to (&it2, start_pos, -1, -1, it2.vpos + 1,
+ MOVE_TO_POS | MOVE_TO_VPOS);
+ }
+ while (!IT_POS_VALID_AFTER_MOVE_P (&it2));
xassert (IT_CHARPOS (*it) >= BEGV);
it3 = it2;
value of nlines is > 0 if continuation lines were involved. */
if (nlines > 0)
move_it_by_lines (it, nlines, 1);
+#if 0
+ /* I think this assert is bogus if buffer contains
+ invisible text or images. KFS. */
xassert (IT_CHARPOS (*it) <= start_pos);
+#endif
}
else
{
a line height of 13 pixels each, recentering with point
on the bottom line will try to move -39/2 = 19 pixels
backward. Try to avoid moving into the first line. */
- && it->current_y - target_y > line_height * 2 / 3
+ && (it->current_y - target_y
+ > min (window_box_height (it->w), line_height * 2 / 3))
&& IT_CHARPOS (*it) > BEGV)
{
TRACE_MOVE ((stderr, " not far enough -> move_vert %d\n",
while (target_y >= line_bottom_y (it) && IT_CHARPOS (*it) < ZV);
}
+#if 0
+ /* I think this assert is bogus if buffer contains
+ invisible text or images. KFS. */
xassert (IT_CHARPOS (*it) >= BEGV);
+#endif
}
}
}
/* If buffer ends in ZV without a newline, move to the start of
the line to satisfy the post-condition. */
if (IT_CHARPOS (*it) == ZV
+ && ZV > BEGV
&& FETCH_BYTE (IT_BYTEPOS (*it) - 1) != '\n')
move_it_by_lines (it, 0, 0);
}
last_height = 0;
}
else if (dvpos > 0)
- move_it_to (it, -1, -1, -1, it->vpos + dvpos, MOVE_TO_VPOS);
+ {
+ move_it_to (it, -1, -1, -1, it->vpos + dvpos, MOVE_TO_VPOS);
+ if (!IT_POS_VALID_AFTER_MOVE_P (it))
+ move_it_to (it, IT_CHARPOS (*it) + 1, -1, -1, -1, MOVE_TO_POS);
+ }
else
{
struct it it2;
int start_charpos, i;
/* Start at the beginning of the screen line containing IT's
- position. */
+ position. This may actually move vertically backwards,
+ in case of overlays, so adjust dvpos accordingly. */
+ dvpos += it->vpos;
move_it_vertically_backward (it, 0);
+ dvpos -= it->vpos;
/* Go back -DVPOS visible lines and reseat the iterator there. */
start_charpos = IT_CHARPOS (*it);
- for (i = -dvpos; i && IT_CHARPOS (*it) > BEGV; --i)
+ for (i = -dvpos; i > 0 && IT_CHARPOS (*it) > BEGV; --i)
back_to_previous_visible_line_start (it);
reseat (it, it->current.pos, 1);
+
+ /* Move further back if we end up in a string or an image. */
+ while (!IT_POS_VALID_AFTER_MOVE_P (it))
+ {
+ /* First try to move to start of display line. */
+ dvpos += it->vpos;
+ move_it_vertically_backward (it, 0);
+ dvpos -= it->vpos;
+ if (IT_POS_VALID_AFTER_MOVE_P (it))
+ break;
+ /* If start of line is still in string or image,
+ move further back. */
+ back_to_previous_visible_line_start (it);
+ reseat (it, it->current.pos, 1);
+ dvpos--;
+ }
+
it->current_x = it->hpos = 0;
/* Above call may have moved too far if continuation lines
terminated with a newline when NLFLAG is non-zero. MULTIBYTE, if
nonzero, means interpret the contents of M as multibyte. This
function calls low-level routines in order to bypass text property
- hooks, etc. which might not be safe to run. */
+ hooks, etc. which might not be safe to run.
+
+ This may GC (insert may run before/after change hooks),
+ so the buffer M must NOT point to a Lisp string. */
void
message_dolog (m, nbytes, nlflag, multibyte)
out any existing message, and let the mini-buffer text show
through.
- The buffer M must continue to exist until after the echo area gets
- cleared or some other message gets displayed there. This means do
- not pass text that is stored in a Lisp string; do not pass text in
- a buffer that was alloca'd. */
+ This may GC, so the buffer M must NOT point to a Lisp string. */
void
message2 (m, nbytes, multibyte)
/* Display an echo area message M with a specified length of NBYTES
bytes. The string may include null characters. If M is not a
string, clear out any existing message, and let the mini-buffer
- text show through. */
+ text show through.
+
+ This function cancels echoing. */
void
message3 (m, nbytes, multibyte)
GCPRO1 (m);
clear_message (1,1);
+ cancel_echoing ();
/* First flush out any partial line written with print. */
message_log_maybe_newline ();
if (STRINGP (m))
- message_dolog (SDATA (m), nbytes, 1, multibyte);
+ {
+ char *buffer;
+ USE_SAFE_ALLOCA;
+
+ SAFE_ALLOCA (buffer, char *, nbytes);
+ bcopy (SDATA (m), buffer, nbytes);
+ message_dolog (buffer, nbytes, 1, multibyte);
+ SAFE_FREE ();
+ }
message3_nolog (m, nbytes, multibyte);
UNGCPRO;
}
-/* The non-logging version of message3. */
+/* The non-logging version of message3.
+ This does not cancel echoing, because it is used for echoing.
+ Perhaps we need to make a separate function for echoing
+ and make this cancel echoing. */
void
message3_nolog (m, nbytes, multibyte)
set_message (NULL, m, nbytes, multibyte);
if (minibuffer_auto_raise)
Fraise_frame (frame);
+ /* Assume we are not echoing.
+ (If we are, echo_now will override this.) */
+ echo_message_buffer = Qnil;
}
else
clear_message (1, 1);
WHICH > 0 means use echo_area_buffer[1]. If that is nil, choose a
suitable buffer from echo_buffer[] and clear it.
- If WHICH < 0, set echo_area_buffer[1] to echo_area_buffer[0], so
- that the current message becomes the last displayed one, make
- choose a suitable buffer for echo_area_buffer[0], and clear it.
-
Value is what FN returns. */
static int
this_one = 0, the_other = 1;
else if (which > 0)
this_one = 1, the_other = 0;
- else
- {
- this_one = 0, the_other = 1;
- clear_buffer_p = 1;
-
- /* We need a fresh one in case the current echo buffer equals
- the one containing the last displayed echo area message. */
- if (!NILP (echo_area_buffer[this_one])
- && EQ (echo_area_buffer[this_one], echo_area_buffer[the_other]))
- echo_area_buffer[this_one] = Qnil;
- }
/* Choose a suitable buffer from echo_buffer[] is we don't
have one. */
int window_height_changed_p = 0;
/* Do this before displaying, so that we have a large enough glyph
- matrix for the display. */
+ matrix for the display. If we can't get enough space for the
+ whole text, display the last N lines. That works by setting w->start. */
window_height_changed_p = resize_mini_window (w, 0);
+ /* Use the starting position chosen by resize_mini_window. */
+ SET_TEXT_POS_FROM_MARKER (start, w->start);
+
/* Display. */
clear_glyph_matrix (w->desired_matrix);
XSETWINDOW (window, w);
- SET_TEXT_POS (start, BEG, BEG_BYTE);
- try_window (window, start);
+ try_window (window, start, 0);
return window_height_changed_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. Value is non-zero if
- the window height has been changed. */
+ only enlarged until W's buffer is empty.
+
+ Set W->start to the right place to begin display. If the whole
+ contents fit, start at the beginning. Otherwise, start so as
+ to make the end of the contents appear. This is particularly
+ important for y-or-n-p, but seems desirable generally.
+
+ Value is non-zero if the window height has been changed. */
int
resize_mini_window (w, exact_p)
xassert (MINI_WINDOW_P (w));
+ /* By default, start display at the beginning. */
+ set_marker_both (w->start, w->buffer,
+ BUF_BEGV (XBUFFER (w->buffer)),
+ BUF_BEGV_BYTE (XBUFFER (w->buffer)));
+
/* Don't resize windows while redisplaying a window; it would
confuse redisplay functions when the size of the window they are
displaying changes from under them. Such a resizing can happen,
if (height > max_height)
{
height = max_height;
- init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
+ init_iterator (&it, w, ZV, ZV_BYTE, NULL, DEFAULT_FACE_ID);
move_it_vertically_backward (&it, (height - 1) * unit);
start = it.current.pos;
}
If S is not null, set the message to the first LEN bytes of S. LEN
zero means use the whole string. MULTIBYTE_P non-zero means S is
- multibyte. Display the message multibyte in that case. */
+ multibyte. Display the message multibyte in that case.
+
+ Doesn't GC, as with_echo_area_buffer binds Qinhibit_modification_hooks
+ to t before calling set_message_1 (which calls insert).
+ */
void
set_message (s, string, nbytes, multibyte_p)
= ((s && multibyte_p)
|| (STRINGP (string) && STRING_MULTIBYTE (string)));
- with_echo_area_buffer (0, -1, set_message_1,
+ with_echo_area_buffer (0, 0, set_message_1,
(EMACS_INT) s, string, nbytes, multibyte_p);
message_buf_print = 0;
help_echo_showing_p = 0;
const char *s = (const char *) a1;
Lisp_Object string = a2;
- xassert (BEG == Z);
-
/* Change multibyteness of the echo buffer appropriately. */
if (message_enable_multibyte
!= !NILP (current_buffer->enable_multibyte_characters))
/* Insert new message at BEG. */
TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
+ Ferase_buffer ();
if (STRINGP (string))
{
else if (!EQ (mini_window, selected_window))
windows_or_buffers_changed++;
- /* Last displayed message is now the current message. */
+ /* The current message is now also the last one displayed. */
echo_area_buffer[1] = echo_area_buffer[0];
- /* Inform read_char that we're not echoing. */
- echo_message_buffer = Qnil;
/* Prevent redisplay optimization in redisplay_internal by resetting
this_line_start_pos. This is done because the mini-buffer now
\f
/***********************************************************************
- Frame Titles
+ Mode Lines and Frame Titles
***********************************************************************/
+/* A buffer for constructing non-propertized mode-line strings and
+ frame titles in it; allocated from the heap in init_xdisp and
+ resized as needed in store_mode_line_noprop_char. */
+
+static char *mode_line_noprop_buf;
-/* The frame title buffering code is also used by Fformat_mode_line.
- So it is not conditioned by HAVE_WINDOW_SYSTEM. */
+/* The buffer's end, and a current output position in it. */
-/* A buffer for constructing frame titles in it; allocated from the
- heap in init_xdisp and resized as needed in store_frame_title_char. */
+static char *mode_line_noprop_buf_end;
+static char *mode_line_noprop_ptr;
-static char *frame_title_buf;
+#define MODE_LINE_NOPROP_LEN(start) \
+ ((mode_line_noprop_ptr - mode_line_noprop_buf) - start)
-/* The buffer's end, and a current output position in it. */
+static enum {
+ MODE_LINE_DISPLAY = 0,
+ MODE_LINE_TITLE,
+ MODE_LINE_NOPROP,
+ MODE_LINE_STRING
+} mode_line_target;
+
+/* Alist that caches the results of :propertize.
+ Each element is (PROPERTIZED-STRING . PROPERTY-LIST). */
+static Lisp_Object mode_line_proptrans_alist;
+
+/* List of strings making up the mode-line. */
+static Lisp_Object mode_line_string_list;
+
+/* Base face property when building propertized mode line string. */
+static Lisp_Object mode_line_string_face;
+static Lisp_Object mode_line_string_face_prop;
+
+
+/* Unwind data for mode line strings */
+
+static Lisp_Object Vmode_line_unwind_vector;
+
+static Lisp_Object
+format_mode_line_unwind_data (obuf, save_proptrans)
+ struct buffer *obuf;
+{
+ Lisp_Object vector;
+
+ /* Reduce consing by keeping one vector in
+ Vwith_echo_area_save_vector. */
+ vector = Vmode_line_unwind_vector;
+ Vmode_line_unwind_vector = Qnil;
+
+ 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;
+
+ if (obuf)
+ XSETBUFFER (AREF (vector, 6), obuf);
+ else
+ AREF (vector, 6) = Qnil;
+
+ return vector;
+}
+
+static Lisp_Object
+unwind_format_mode_line (vector)
+ Lisp_Object vector;
+{
+ mode_line_target = XINT (AREF (vector, 0));
+ mode_line_noprop_ptr = mode_line_noprop_buf + XINT (AREF (vector, 1));
+ mode_line_string_list = AREF (vector, 2);
+ if (! EQ (AREF (vector, 3), Qt))
+ mode_line_proptrans_alist = AREF (vector, 3);
+ mode_line_string_face = AREF (vector, 4);
+ mode_line_string_face_prop = AREF (vector, 5);
+
+ if (!NILP (AREF (vector, 6)))
+ {
+ set_buffer_internal_1 (XBUFFER (AREF (vector, 6)));
+ AREF (vector, 6) = Qnil;
+ }
-static char *frame_title_buf_end;
-static char *frame_title_ptr;
+ Vmode_line_unwind_vector = vector;
+ return Qnil;
+}
-/* Store a single character C for the frame title in frame_title_buf.
- Re-allocate frame_title_buf if necessary. */
+/* Store a single character C for the frame title in mode_line_noprop_buf.
+ Re-allocate mode_line_noprop_buf if necessary. */
static void
#ifdef PROTOTYPES
-store_frame_title_char (char c)
+store_mode_line_noprop_char (char c)
#else
-store_frame_title_char (c)
+store_mode_line_noprop_char (c)
char c;
#endif
{
/* If output position has reached the end of the allocated buffer,
double the buffer's size. */
- if (frame_title_ptr == frame_title_buf_end)
+ if (mode_line_noprop_ptr == mode_line_noprop_buf_end)
{
- int len = frame_title_ptr - frame_title_buf;
- int new_size = 2 * len * sizeof *frame_title_buf;
- frame_title_buf = (char *) xrealloc (frame_title_buf, new_size);
- frame_title_buf_end = frame_title_buf + new_size;
- frame_title_ptr = frame_title_buf + len;
+ int len = MODE_LINE_NOPROP_LEN (0);
+ int new_size = 2 * len * sizeof *mode_line_noprop_buf;
+ mode_line_noprop_buf = (char *) xrealloc (mode_line_noprop_buf, new_size);
+ mode_line_noprop_buf_end = mode_line_noprop_buf + new_size;
+ mode_line_noprop_ptr = mode_line_noprop_buf + len;
}
- *frame_title_ptr++ = c;
+ *mode_line_noprop_ptr++ = c;
}
-/* Store part of a frame title in frame_title_buf, beginning at
- frame_title_ptr. STR is the string to store. Do not copy
+/* Store part of a frame title in mode_line_noprop_buf, beginning at
+ mode_line_noprop_ptr. STR is the string to store. Do not copy
characters that yield more columns than PRECISION; PRECISION <= 0
means copy the whole string. Pad with spaces until FIELD_WIDTH
number of characters have been copied; FIELD_WIDTH <= 0 means don't
frame title. */
static int
-store_frame_title (str, field_width, precision)
+store_mode_line_noprop (str, field_width, precision)
const unsigned char *str;
int field_width, precision;
{
nbytes = strlen (str);
n += c_string_width (str, nbytes, precision, &dummy, &nbytes);
while (nbytes--)
- store_frame_title_char (*str++);
+ store_mode_line_noprop_char (*str++);
/* Fill up with spaces until FIELD_WIDTH reached. */
while (field_width > 0
&& n < field_width)
{
- store_frame_title_char (' ');
+ store_mode_line_noprop_char (' ');
++n;
}
return n;
}
+/***********************************************************************
+ Frame Titles
+ ***********************************************************************/
+
#ifdef HAVE_WINDOW_SYSTEM
/* Set the title of FRAME, if it has changed. The title format is
/* Do we have more than one visible frame on this X display? */
Lisp_Object tail;
Lisp_Object fmt;
- struct buffer *obuf;
+ int title_start;
+ char *title;
int len;
struct it it;
+ int count = SPECPDL_INDEX ();
for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
{
multiple_frames = CONSP (tail);
/* Switch to the buffer of selected window of the frame. Set up
- frame_title_ptr so that display_mode_element will output into it;
- then display the title. */
- obuf = current_buffer;
+ mode_line_target so that display_mode_element will output into
+ mode_line_noprop_buf; then display the title. */
+ record_unwind_protect (unwind_format_mode_line,
+ format_mode_line_unwind_data (current_buffer, 0));
+
set_buffer_internal_1 (XBUFFER (XWINDOW (f->selected_window)->buffer));
fmt = FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format;
- frame_title_ptr = frame_title_buf;
+
+ mode_line_target = MODE_LINE_TITLE;
+ title_start = MODE_LINE_NOPROP_LEN (0);
init_iterator (&it, XWINDOW (f->selected_window), -1, -1,
NULL, DEFAULT_FACE_ID);
display_mode_element (&it, 0, -1, -1, fmt, Qnil, 0);
- len = frame_title_ptr - frame_title_buf;
- frame_title_ptr = NULL;
- set_buffer_internal_1 (obuf);
+ len = MODE_LINE_NOPROP_LEN (title_start);
+ title = mode_line_noprop_buf + title_start;
+ unbind_to (count, Qnil);
/* Set the title only if it's changed. This avoids consing in
the common case where it hasn't. (If it turns out that we've
higher level than this.) */
if (! STRINGP (f->name)
|| SBYTES (f->name) != len
- || bcmp (frame_title_buf, SDATA (f->name), len) != 0)
- x_implicitly_set_name (f, make_string (frame_title_buf, len), Qnil);
+ || bcmp (title, SDATA (f->name), len) != 0)
+ x_implicitly_set_name (f, make_string (title, len), Qnil);
}
}
{
Lisp_Object tail, frame;
int count = SPECPDL_INDEX ();
+ /* 1 means that update_menu_bar has run its hooks
+ so any further calls to update_menu_bar shouldn't do so again. */
+ int menu_bar_hooks_run = 0;
- record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ record_unwind_save_match_data ();
FOR_EACH_FRAME (tail, frame)
{
}
GCPRO1 (tail);
- update_menu_bar (f, 0);
+ menu_bar_hooks_run = update_menu_bar (f, 0, menu_bar_hooks_run);
#ifdef HAVE_WINDOW_SYSTEM
update_tool_bar (f, 0);
+#ifdef MAC_OS
+ mac_update_title_bar (f, 0);
+#endif
#endif
UNGCPRO;
}
else
{
struct frame *sf = SELECTED_FRAME ();
- update_menu_bar (sf, 1);
+ update_menu_bar (sf, 1, 0);
#ifdef HAVE_WINDOW_SYSTEM
update_tool_bar (sf, 1);
+#ifdef MAC_OS
+ mac_update_title_bar (sf, 1);
+#endif
#endif
}
before we start to fill in any display lines, because it can call
eval.
- If SAVE_MATCH_DATA is non-zero, we must save and restore it here. */
+ If SAVE_MATCH_DATA is non-zero, we must save and restore it here.
-static void
-update_menu_bar (f, save_match_data)
+ If HOOKS_RUN is 1, that means a previous call to update_menu_bar
+ already ran the menu bar hooks for this redisplay, so there
+ is no need to run them again. The return value is the
+ updated value of this flag, to pass to the next call. */
+
+static int
+update_menu_bar (f, save_match_data, hooks_run)
struct frame *f;
int save_match_data;
+ int hooks_run;
{
Lisp_Object window;
register struct window *w;
happen when, for instance, an activate-menubar-hook causes a
redisplay. */
if (inhibit_menubar_update)
- return;
+ return hooks_run;
window = FRAME_SELECTED_WINDOW (f);
w = XWINDOW (window);
set_buffer_internal_1 (XBUFFER (w->buffer));
if (save_match_data)
- record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ record_unwind_save_match_data ();
if (NILP (Voverriding_local_map_menu_flag))
{
specbind (Qoverriding_terminal_local_map, Qnil);
specbind (Qoverriding_local_map, Qnil);
}
- /* Run the Lucid hook. */
- safe_run_hooks (Qactivate_menubar_hook);
+ if (!hooks_run)
+ {
+ /* Run the Lucid hook. */
+ safe_run_hooks (Qactivate_menubar_hook);
+
+ /* If it has changed current-menubar from previous value,
+ really recompute the menu-bar from the value. */
+ if (! NILP (Vlucid_menu_bar_dirty_flag))
+ call0 (Qrecompute_lucid_menubar);
+
+ safe_run_hooks (Qmenu_bar_update_hook);
- /* If it has changed current-menubar from previous value,
- really recompute the menu-bar from the value. */
- if (! NILP (Vlucid_menu_bar_dirty_flag))
- call0 (Qrecompute_lucid_menubar);
+ hooks_run = 1;
+ }
- safe_run_hooks (Qmenu_bar_update_hook);
+ XSETFRAME (Vmenu_updating_frame, f);
FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
/* 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. */
set_buffer_internal_1 (prev);
}
}
+
+ return hooks_run;
}
/* Save match data, if we must. */
if (save_match_data)
- record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ record_unwind_save_match_data ();
/* Make sure that we don't accidentally use bogus keymaps. */
if (NILP (Voverriding_local_map_menu_flag))
&new_n_tool_bar);
/* Redisplay the tool-bar if we changed it. */
- if (NILP (Fequal (new_tool_bar, f->tool_bar_items)))
+ if (new_n_tool_bar != f->n_tool_bar_items
+ || NILP (Fequal (new_tool_bar, f->tool_bar_items)))
{
/* Redisplay that happens asynchronously due to an expose event
may access f->tool_bar_items. Make sure we update both
}
-/* 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;
+ }
}
}
static Lisp_Object
-overlay_arrow_string_or_property (var, pbitmap)
+overlay_arrow_string_or_property (var)
Lisp_Object var;
- int *pbitmap;
{
- Lisp_Object pstr = Fget (var, Qoverlay_arrow_string);
- Lisp_Object bitmap;
+ Lisp_Object val;
- if (pbitmap)
- {
- *pbitmap = 0;
- if (bitmap = Fget (var, Qoverlay_arrow_bitmap), INTEGERP (bitmap))
- *pbitmap = XINT (bitmap);
- }
+ if (val = Fget (var, Qoverlay_arrow_string), STRINGP (val))
+ return val;
- if (!NILP (pstr))
- return pstr;
return Voverlay_arrow_string;
}
continue;
if (! EQ (COERCE_MARKER (val),
Fget (var, Qlast_arrow_position))
- || ! (pstr = overlay_arrow_string_or_property (var, 0),
+ || ! (pstr = overlay_arrow_string_or_property (var),
EQ (pstr, Fget (var, Qlast_arrow_string))))
return 1;
}
Fput (var, Qlast_arrow_position,
COERCE_MARKER (val));
Fput (var, Qlast_arrow_string,
- overlay_arrow_string_or_property (var, 0));
+ overlay_arrow_string_or_property (var));
}
else if (up_to_date < 0
|| !NILP (Fget (var, Qlast_arrow_position)))
/* Return overlay arrow string to display at row.
- Return t if display as bitmap in left fringe.
+ Return integer (bitmap number) for arrow bitmap in left fringe.
Return nil if no overlay arrow. */
static Lisp_Object
-overlay_arrow_at_row (it, row, pbitmap)
+overlay_arrow_at_row (it, row)
struct it *it;
struct glyph_row *row;
- int *pbitmap;
{
Lisp_Object vlist;
&& current_buffer == XMARKER (val)->buffer
&& (MATRIX_ROW_START_CHARPOS (row) == marker_position (val)))
{
- val = overlay_arrow_string_or_property (var, pbitmap);
if (FRAME_WINDOW_P (it->f)
&& WINDOW_LEFT_FRINGE_WIDTH (it->w) > 0)
- return Qt;
- if (STRINGP (val))
- return val;
- break;
+ {
+#ifdef HAVE_WINDOW_SYSTEM
+ if (val = Fget (var, Qoverlay_arrow_bitmap), SYMBOLP (val))
+ {
+ int fringe_bitmap;
+ if ((fringe_bitmap = lookup_fringe_bitmap (val)) != 0)
+ return make_number (fringe_bitmap);
+ }
+#endif
+ return make_number (-1); /* Use default arrow bitmap */
+ }
+ return overlay_arrow_string_or_property (var);
}
}
- *pbitmap = 0;
return Qnil;
}
(BUFFER_LOCAL_VALUEP (val)
|| SOME_BUFFER_LOCAL_VALUEP (val)))
&& XBUFFER_LOCAL_VALUE (val)->check_frame)
- Fsymbol_value (sym);
+ /* 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))
(BUFFER_LOCAL_VALUEP (val)
|| SOME_BUFFER_LOCAL_VALUEP (val)))
&& XBUFFER_LOCAL_VALUE (val)->check_frame)
- Fsymbol_value (sym);
+ find_symbol_value (sym);
}
int preserve_echo_area;
{
struct window *w = XWINDOW (selected_window);
- struct frame *f = XFRAME (w->frame);
+ struct frame *f;
int pause;
int must_finish = 0;
struct text_pos tlbufpos, tlendpos;
int number_of_visible_frames;
int count;
- struct frame *sf = SELECTED_FRAME ();
+ struct frame *sf;
int polling_stopped_here = 0;
/* Non-zero means redisplay has to consider all windows on all
initialized, or redisplay is explicitly turned off by setting
Vinhibit_redisplay. */
if (noninteractive
- || !NILP (Vinhibit_redisplay)
- || !f->glyphs_initialized_p)
+ || !NILP (Vinhibit_redisplay))
+ return;
+
+ /* Don't examine these until after testing Vinhibit_redisplay.
+ When Emacs is shutting down, perhaps because its connection to
+ X has dropped, we should not look at them at all. */
+ f = XFRAME (w->frame);
+ sf = SELECTED_FRAME ();
+
+ if (!f->glyphs_initialized_p)
return;
/* The flag redisplay_performed_directly_p is set by
++redisplaying_p;
specbind (Qinhibit_free_realized_faces, Qnil);
+ {
+ Lisp_Object tail, frame;
+
+ FOR_EACH_FRAME (tail, frame)
+ {
+ struct frame *f = XFRAME (frame);
+ f->already_hscrolled_p = 0;
+ }
+ }
+
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. */
clear_garbaged_frames ();
/* Build menubar and tool-bar items. */
- prepare_menu_bars ();
+ if (NILP (Vmemory_full))
+ prepare_menu_bars ();
if (windows_or_buffers_changed)
update_mode_lines++;
CHARPOS (this_line_start_pos) = 0;
consider_all_windows_p |= buffer_shared > 1;
++clear_face_cache_count;
-
+#ifdef HAVE_WINDOW_SYSTEM
+ ++clear_image_cache_count;
+#endif
/* Build desired matrices, and update the display. If
consider_all_windows_p is non-zero, do it for all windows on all
if (consider_all_windows_p)
{
Lisp_Object tail, frame;
- int i, n = 0, size = 50;
- struct frame **updated
- = (struct frame **) alloca (size * sizeof *updated);
- /* Clear the face cache eventually. */
- if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT)
- {
- clear_face_cache (0);
- clear_face_cache_count = 0;
- }
+ FOR_EACH_FRAME (tail, frame)
+ XFRAME (frame)->updated_p = 0;
/* Recompute # windows showing selected buffer. This will be
incremented each time such a window is displayed. */
variables. */
select_frame_for_redisplay (frame);
-#ifdef HAVE_WINDOW_SYSTEM
- if (clear_face_cache_count % 50 == 0
- && FRAME_WINDOW_P (f))
- clear_image_cache (f, 0);
-#endif /* HAVE_WINDOW_SYSTEM */
-
/* Mark all the scroll bars to be removed; we'll redeem
the ones we want when we redisplay their windows. */
if (condemn_scroll_bars_hook)
if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
{
/* See if we have to hscroll. */
- if (hscroll_windows (f->root_window))
- goto retry;
+ if (!f->already_hscrolled_p)
+ {
+ f->already_hscrolled_p = 1;
+ if (hscroll_windows (f->root_window))
+ goto retry;
+ }
/* Prevent various kinds of signals during display
update. stdio is not robust about handling
break;
#endif
- if (n == size)
- {
- int nbytes = size * sizeof *updated;
- struct frame **p = (struct frame **) alloca (2 * nbytes);
- bcopy (updated, p, nbytes);
- size *= 2;
- }
-
- updated[n++] = f;
+ f->updated_p = 1;
}
}
}
/* Do the mark_window_display_accurate after all windows have
been redisplayed because this call resets flags in buffers
which are needed for proper redisplay. */
- for (i = 0; i < n; ++i)
+ FOR_EACH_FRAME (tail, frame)
{
- struct frame *f = updated[i];
- mark_window_display_accurate (f->root_window, 1);
- if (frame_up_to_date_hook)
- frame_up_to_date_hook (f);
+ struct frame *f = XFRAME (frame);
+ if (f->updated_p)
+ {
+ mark_window_display_accurate (f->root_window, 1);
+ if (frame_up_to_date_hook)
+ frame_up_to_date_hook (f);
+ }
}
}
}
if (windows_or_buffers_changed && !pause)
goto retry;
+ /* Clear the face cache eventually. */
+ if (consider_all_windows_p)
+ {
+ if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT)
+ {
+ clear_face_cache (0);
+ clear_face_cache_count = 0;
+ }
+#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_cache_count = 0;
+ }
+#endif /* HAVE_WINDOW_SYSTEM */
+ }
+
end_of_redisplay:
unbind_to (count, Qnil);
RESUME_POLLING;
/* 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;
}
as if point had gone off the screen. */
static int
-make_cursor_line_fully_visible (w, force_p)
+cursor_row_fully_visible_p (w, force_p, current_matrix_p)
struct window *w;
int force_p;
+ int current_matrix_p;
{
struct glyph_matrix *matrix;
struct glyph_row *row;
if (w->cursor.vpos < 0)
return 1;
- matrix = w->desired_matrix;
+ matrix = current_matrix_p ? w->current_matrix : w->desired_matrix;
row = MATRIX_ROW (matrix, w->cursor.vpos);
/* If the cursor row is not partially visible, there's nothing to do. */
window_height = window_box_height (w);
if (row->height >= window_height)
{
- if (!force_p || w->vscroll)
+ if (!force_p || MINI_WINDOW_P (w)
+ || w->vscroll || w->cursor.vpos == 0)
return 1;
}
return 0;
/* Display the window. Give up if new fonts are loaded, or if point
doesn't appear. */
- if (!try_window (window, startp))
+ if (!try_window (window, startp, 0))
rc = SCROLLING_NEED_LARGER_MATRICES;
else if (w->cursor.vpos < 0)
{
/* 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, extra_scroll_margin_lines <= 1))
+ if (! cursor_row_fully_visible_p (w, extra_scroll_margin_lines <= 1, 0))
{
clear_glyph_matrix (w->desired_matrix);
++extra_scroll_margin_lines;
while (!row->mode_line_p
&& (MATRIX_ROW_START_CHARPOS (row) > PT
|| (MATRIX_ROW_START_CHARPOS (row) == PT
- && MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P (row)))
+ && (MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P (row)
+ || (/* STARTS_IN_MIDDLE_OF_STRING_P (row) */
+ row > w->current_matrix->rows
+ && (row-1)->ends_in_newline_from_string_p))))
&& (row->y > top_scroll_margin
|| CHARPOS (startp) == BEGV))
{
&& CHARPOS (startp) != BEGV)
scroll_p = 1;
}
+ else
+ {
+ /* Cursor did not move. So don't scroll even if cursor line
+ is partially visible, as it was so before. */
+ rc = CURSOR_MOVEMENT_SUCCESS;
+ }
if (PT < MATRIX_ROW_START_CHARPOS (row)
|| PT > MATRIX_ROW_END_CHARPOS (row))
/* if PT is not in the glyph row, give up. */
rc = CURSOR_MOVEMENT_MUST_SCROLL;
}
- else if (MATRIX_ROW_PARTIALLY_VISIBLE_P (w, row)
+ else if (rc != CURSOR_MOVEMENT_SUCCESS
+ && MATRIX_ROW_PARTIALLY_VISIBLE_P (w, row)
&& make_cursor_line_fully_visible_p)
{
if (PT == MATRIX_ROW_END_CHARPOS (row)
else
{
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
- if (!make_cursor_line_fully_visible (w, 0))
+ if (!cursor_row_fully_visible_p (w, 0, 1))
rc = CURSOR_MOVEMENT_MUST_SCROLL;
else
rc = CURSOR_MOVEMENT_SUCCESS;
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));
}
}
}
int temp_scroll_step = 0;
int count = SPECPDL_INDEX ();
int rc;
- int centering_position;
+ int centering_position = -1;
int last_line_misfit = 0;
SET_TEXT_POS (lpoint, PT, PT_BYTE);
/* 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,
{
/* We set this later on if we have to adjust point. */
int new_vpos = -1;
+ int val;
w->force_start = Qnil;
w->vscroll = 0;
/* Redisplay, then check if cursor has been set during the
redisplay. Give up if new fonts were loaded. */
- if (!try_window (window, startp))
+ val = try_window (window, startp, 1);
+ if (!val)
{
w->force_start = Qt;
clear_glyph_matrix (w->desired_matrix);
goto need_larger_matrices;
}
+ /* Point was outside the scroll margins. */
+ if (val < 0)
+ new_vpos = window_box_height (w) / 2;
if (w->cursor.vpos < 0 && !w->frozen_window_start_p)
{
new_vpos = window_box_height (w) / 2;
}
- if (!make_cursor_line_fully_visible (w, 0))
+ if (!cursor_row_fully_visible_p (w, 0, 0))
{
/* Point does appear, but on a line partly visible at end of window.
Move it back to a fully-visible line. */
&& !NILP (current_buffer->mark_active))
{
clear_glyph_matrix (w->desired_matrix);
- if (!try_window (window, startp))
+ if (!try_window (window, startp, 0))
goto need_larger_matrices;
}
}
|| (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
= try_window_reusing_current_matrix (w)))
{
IF_DEBUG (debug_method_add (w, "1"));
- try_window (window, startp);
+ if (try_window (window, startp, 1) < 0)
+ /* -1 means we need to scroll.
+ 0 means we need new matrices, but fonts_changed_p
+ is set in that case, so we will detect it below. */
+ goto try_to_scroll;
}
if (fonts_changed_p)
/* Forget any recorded base line for line number display. */
w->base_line_number = Qnil;
- if (!make_cursor_line_fully_visible (w, 1))
+ if (!cursor_row_fully_visible_p (w, 1, 0))
{
clear_glyph_matrix (w->desired_matrix);
last_line_misfit = 1;
/* Finally, just choose place to start which centers point */
recenter:
- centering_position = window_box_height (w) / 2;
-
- point_at_top:
- /* Jump here with centering_position already set to 0. */
+ if (centering_position < 0)
+ centering_position = window_box_height (w) / 2;
#if GLYPH_DEBUG
debug_method_add (w, "recenter");
{
init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
move_it_vertically_backward (&it, 0);
+#if 0
+ /* I think this assert is bogus if buffer contains
+ invisible text or images. KFS. */
xassert (IT_CHARPOS (it) <= PT);
+#endif
it.current_y = 0;
}
|| MINI_WINDOW_P (w)
|| !(used_current_matrix_p
= try_window_reusing_current_matrix (w)))
- try_window (window, startp);
+ try_window (window, startp, 0);
/* If new fonts have been loaded (due to fontsets), give up. We
have to start a new redisplay since we need to re-adjust glyph
{
clear_glyph_matrix (w->desired_matrix);
move_it_by_lines (&it, 1, 0);
- try_window (window, it.current.pos);
+ try_window (window, it.current.pos, 0);
}
else if (PT < IT_CHARPOS (it))
{
clear_glyph_matrix (w->desired_matrix);
move_it_by_lines (&it, -1, 0);
- try_window (window, it.current.pos);
+ try_window (window, it.current.pos, 0);
}
else
{
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
}
- if (!make_cursor_line_fully_visible (w, centering_position > 0))
+ if (!cursor_row_fully_visible_p (w, 0, 0))
{
/* If vscroll is enabled, disable it and try again. */
if (w->vscroll)
visible, if it can be done. */
if (centering_position == 0)
goto done;
+
clear_glyph_matrix (w->desired_matrix);
centering_position = 0;
- goto point_at_top;
+ goto recenter;
}
done:
#ifdef HAVE_WINDOW_SYSTEM
if (FRAME_WINDOW_P (f)
- && update_window_fringes (w, 0)
- && !just_this_one_p
- && (used_current_matrix_p || overlay_arrow_seen)
- && !w->pseudo_window_p)
+ && update_window_fringes (w, (just_this_one_p
+ || (!used_current_matrix_p && !overlay_arrow_seen)
+ || w->pseudo_window_p)))
{
update_begin (f);
BLOCK_INPUT;
/* Build the complete desired matrix of WINDOW with a window start
- buffer position POS. Value is non-zero if successful. It is zero
- if fonts were loaded during redisplay which makes re-adjusting
- glyph matrices necessary. */
+ buffer position POS.
+
+ Value is 1 if successful. It is zero if fonts were loaded during
+ redisplay which makes re-adjusting glyph matrices necessary, and -1
+ if point would appear in the scroll margins.
+ (We check that only if CHECK_MARGINS is nonzero. */
int
-try_window (window, pos)
+try_window (window, pos, check_margins)
Lisp_Object window;
struct text_pos pos;
+ int check_margins;
{
struct window *w = XWINDOW (window);
struct it it;
return 0;
}
+ /* Don't let the cursor end in the scroll margins. */
+ if (check_margins
+ && !MINI_WINDOW_P (w))
+ {
+ int this_scroll_margin;
+
+ this_scroll_margin = max (0, scroll_margin);
+ this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
+ this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
+
+ if ((w->cursor.y >= 0 /* not vscrolled */
+ && w->cursor.y < this_scroll_margin
+ && CHARPOS (pos) > BEGV
+ && IT_CHARPOS (it) < ZV)
+ /* rms: considering make_cursor_line_fully_visible_p here
+ seems to give wrong results. We don't want to recenter
+ when the last line is partly visible, we want to allow
+ that case to be handled in the usual way. */
+ || (w->cursor.y + 1) > it.last_visible_y)
+ {
+ w->cursor.vpos = -1;
+ clear_glyph_matrix (w->desired_matrix);
+ return -1;
+ }
+ }
+
/* If bottom moved off end of frame, change mode line percentage. */
if (XFASTINT (w->window_end_pos) <= 0
&& Z != IT_CHARPOS (it))
/* Disable lines in the current matrix which are now
below the window. */
for (++row; row < bottom_row; ++row)
- row->enabled_p = 0;
+ row->enabled_p = row->mode_line_p = 0;
}
/* Update window_end_pos etc.; last_reused_text_row is the last
starts at a minimum position >= last_unchanged_pos_old. */
for (; row > first_text_row; --row)
{
+ /* This used to abort, but it can happen.
+ It is ok to just stop the search instead here. KFS. */
if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
- abort ();
+ break;
if (MATRIX_ROW_START_CHARPOS (row) >= last_unchanged_pos_old)
row_found = row;
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><O\\CTZFesm X Y W H V A P\n");
- fprintf (stderr, "=======================================================================\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%1.1d\
+ fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d\
%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d %4d %4d %4d %4d %4d %4d %4d\n",
vpos,
MATRIX_ROW_START_CHARPOS (row),
row->enabled_p,
row->truncated_on_left_p,
row->truncated_on_right_p,
- row->overlay_arrow_p,
row->continued_p,
MATRIX_ROW_CONTINUATION_LINE_P (row),
row->displays_text_p,
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)
if (PT == MATRIX_ROW_END_CHARPOS (row))
{
/* If the row ends with a newline from a string, we don't want
- the cursor there (if the row is continued it doesn't end in a
- newline). */
+ the cursor there, but we still want it at the start of the
+ string if the string starts in this row.
+ If the row is continued it doesn't end in a newline. */
if (CHARPOS (row->end.string_pos) >= 0)
- cursor_row_p = row->continued_p;
+ cursor_row_p = (row->continued_p
+ || PT >= MATRIX_ROW_START_CHARPOS (row));
else if (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
{
/* If the row ends in middle of a real character,
struct it *it;
{
struct glyph_row *row = it->glyph_row;
- int overlay_arrow_bitmap;
Lisp_Object overlay_arrow_string;
/* We always start displaying at hpos zero even if hscrolled. */
produce_special_glyphs (it, IT_CONTINUATION);
row->continued_p = 1;
+ it->current_x = x_before;
it->continuation_lines_width += x;
+ extend_face_to_end_of_line (it);
if (nglyphs > 1 && i > 0)
{
mark this glyph row as the one containing the overlay arrow.
This is clearly a mess with variable size fonts. It would be
better to let it be displayed like cursors under X. */
- if (! overlay_arrow_seen
- && (overlay_arrow_string
- = overlay_arrow_at_row (it, row, &overlay_arrow_bitmap),
+ if ((row->displays_text_p || !overlay_arrow_seen)
+ && (overlay_arrow_string = overlay_arrow_at_row (it, row),
!NILP (overlay_arrow_string)))
{
/* Overlay arrow in window redisplay is a fringe bitmap. */
}
else
{
- it->w->overlay_arrow_bitmap = overlay_arrow_bitmap;
- row->overlay_arrow_p = 1;
+ xassert (INTEGERP (overlay_arrow_string));
+ row->overlay_arrow_bitmap = XINT (overlay_arrow_string);
}
overlay_arrow_seen = 1;
}
{
struct it it;
struct face *face;
+ int count = SPECPDL_INDEX ();
init_iterator (&it, w, -1, -1, NULL, face_id);
prepare_desired_row (it.glyph_row);
/* Force the mode-line to be displayed in the default face. */
it.base_face_id = it.face_id = DEFAULT_FACE_ID;
+ record_unwind_protect (unwind_format_mode_line,
+ format_mode_line_unwind_data (NULL, 0));
+
+ mode_line_target = MODE_LINE_DISPLAY;
+
/* Temporarily make frame's keyboard the current kboard so that
kboard-local variables in the mode_line_format will get the right
values. */
push_frame_kboard (it.f);
+ record_unwind_save_match_data ();
display_mode_element (&it, 0, 0, 0, format, Qnil, 0);
pop_frame_kboard ();
+ unbind_to (count, Qnil);
+
/* Fill up with spaces. */
display_string (" ", Qnil, Qnil, 0, 0, &it, 10000, -1, -1, 0);
return it.glyph_row->height;
}
-/* Alist that caches the results of :propertize.
- Each element is (PROPERTIZED-STRING . PROPERTY-LIST). */
-Lisp_Object mode_line_proptrans_alist;
+/* Move element ELT in LIST to the front of LIST.
+ Return the updated list. */
-/* List of strings making up the mode-line. */
-Lisp_Object mode_line_string_list;
+static Lisp_Object
+move_elt_to_front (elt, list)
+ Lisp_Object elt, list;
+{
+ register Lisp_Object tail, prev;
+ register Lisp_Object tem;
-/* Base face property when building propertized mode line string. */
-static Lisp_Object mode_line_string_face;
-static Lisp_Object mode_line_string_face_prop;
+ tail = list;
+ prev = Qnil;
+ while (CONSP (tail))
+ {
+ tem = XCAR (tail);
+
+ if (EQ (elt, tem))
+ {
+ /* Splice out the link TAIL. */
+ if (NILP (prev))
+ list = XCDR (tail);
+ else
+ Fsetcdr (prev, XCDR (tail));
+
+ /* Now make it the first. */
+ Fsetcdr (tail, list);
+ return tail;
+ }
+ else
+ prev = tail;
+ tail = XCDR (tail);
+ QUIT;
+ }
+ /* Not found--return unchanged LIST. */
+ return list;
+}
/* Contribute ELT to the mode line for window IT->w. How it
translates into text depends on its data type.
If RISKY is nonzero, remove (disregard) any properties in any string
we encounter, and ignore :eval and :propertize.
- If the global variable `frame_title_ptr' is non-NULL, then the output
- is passed to `store_frame_title' instead of `display_string'. */
+ The global variable `mode_line_target' determines whether the
+ output is passed to `store_mode_line_noprop',
+ `store_mode_line_string', or `display_string'. */
static int
display_mode_element (it, depth, field_width, precision, elt, props, risky)
{
/* A string: output it and check for %-constructs within it. */
unsigned char c;
- const unsigned char *this, *lisp_string;
+ int offset = 0;
- if (!NILP (props) || risky)
+ if (SCHARS (elt) > 0
+ && (!NILP (props) || risky))
{
Lisp_Object oprops, aelt;
oprops = Ftext_properties_at (make_number (0), elt);
aelt = Fassoc (elt, mode_line_proptrans_alist);
if (! NILP (aelt) && !NILP (Fequal (props, XCDR (aelt))))
{
- mode_line_proptrans_alist
- = Fcons (aelt, Fdelq (aelt, mode_line_proptrans_alist));
+ /* AELT is what we want. Move it to the front
+ without consing. */
elt = XCAR (aelt);
+ mode_line_proptrans_alist
+ = move_elt_to_front (aelt, mode_line_proptrans_alist);
}
else
{
Lisp_Object tem;
+ /* If AELT has the wrong props, it is useless.
+ so get rid of it. */
+ if (! NILP (aelt))
+ mode_line_proptrans_alist
+ = Fdelq (aelt, mode_line_proptrans_alist);
+
elt = Fcopy_sequence (elt);
Fset_text_properties (make_number (0), Flength (elt),
props, elt);
}
}
- this = SDATA (elt);
- lisp_string = this;
+ offset = 0;
if (literal)
{
prec = precision - n;
- if (frame_title_ptr)
- n += store_frame_title (SDATA (elt), -1, prec);
- else if (!NILP (mode_line_string_list))
- n += store_mode_line_string (NULL, elt, 1, 0, prec, Qnil);
- else
- n += display_string (NULL, elt, Qnil, 0, 0, it,
- 0, prec, 0, STRING_MULTIBYTE (elt));
+ switch (mode_line_target)
+ {
+ case MODE_LINE_NOPROP:
+ case MODE_LINE_TITLE:
+ n += store_mode_line_noprop (SDATA (elt), -1, prec);
+ break;
+ case MODE_LINE_STRING:
+ n += store_mode_line_string (NULL, elt, 1, 0, prec, Qnil);
+ break;
+ case MODE_LINE_DISPLAY:
+ n += display_string (NULL, elt, Qnil, 0, 0, it,
+ 0, prec, 0, STRING_MULTIBYTE (elt));
+ break;
+ }
break;
}
+ /* Handle the non-literal case. */
+
while ((precision <= 0 || n < precision)
- && *this
- && (frame_title_ptr
- || !NILP (mode_line_string_list)
+ && SREF (elt, offset) != 0
+ && (mode_line_target != MODE_LINE_DISPLAY
|| it->current_x < it->last_visible_x))
{
- const unsigned char *last = this;
+ int last_offset = offset;
/* Advance to end of string or next format specifier. */
- while ((c = *this++) != '\0' && c != '%')
+ while ((c = SREF (elt, offset++)) != '\0' && c != '%')
;
- if (this - 1 != last)
+ if (offset - 1 != last_offset)
{
int nchars, nbytes;
/* Output to end of string or up to '%'. Field width
is length of string. Don't output more than
PRECISION allows us. */
- --this;
+ offset--;
- prec = c_string_width (last, this - last, precision - n,
+ prec = c_string_width (SDATA (elt) + last_offset,
+ offset - last_offset, precision - n,
&nchars, &nbytes);
- if (frame_title_ptr)
- n += store_frame_title (last, 0, prec);
- else if (!NILP (mode_line_string_list))
- {
- int bytepos = last - lisp_string;
- int charpos = string_byte_to_char (elt, bytepos);
- int endpos = (precision <= 0
- ? string_byte_to_char (elt,
- this - lisp_string)
- : charpos + nchars);
-
- n += store_mode_line_string (NULL,
- Fsubstring (elt, make_number (charpos),
- make_number (endpos)),
- 0, 0, 0, Qnil);
- }
- else
+ switch (mode_line_target)
{
- int bytepos = last - lisp_string;
- int charpos = string_byte_to_char (elt, bytepos);
- n += display_string (NULL, elt, Qnil, 0, charpos,
- it, 0, prec, 0,
- STRING_MULTIBYTE (elt));
+ case MODE_LINE_NOPROP:
+ case MODE_LINE_TITLE:
+ n += store_mode_line_noprop (SDATA (elt) + last_offset, 0, prec);
+ break;
+ case MODE_LINE_STRING:
+ {
+ int bytepos = last_offset;
+ int charpos = string_byte_to_char (elt, bytepos);
+ int endpos = (precision <= 0
+ ? string_byte_to_char (elt, offset)
+ : charpos + nchars);
+
+ n += store_mode_line_string (NULL,
+ Fsubstring (elt, make_number (charpos),
+ make_number (endpos)),
+ 0, 0, 0, Qnil);
+ }
+ break;
+ case MODE_LINE_DISPLAY:
+ {
+ 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, nchars, 0,
+ STRING_MULTIBYTE (elt));
+ }
+ break;
}
}
else /* c == '%' */
{
- const unsigned char *percent_position = this;
+ int percent_position = offset;
/* Get the specified minimum width. Zero means
don't pad. */
field = 0;
- while ((c = *this++) >= '0' && c <= '9')
+ while ((c = SREF (elt, offset++)) >= '0' && c <= '9')
field = field * 10 + c - '0';
/* Don't pad beyond the total padding allowed. */
int bytepos, charpos;
unsigned char *spec;
- bytepos = percent_position - lisp_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);
- if (frame_title_ptr)
- n += store_frame_title (spec, field, prec);
- else if (!NILP (mode_line_string_list))
- {
- int len = strlen (spec);
- Lisp_Object tem = 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);
- }
- else
+ switch (mode_line_target)
{
- int nglyphs_before, nwritten;
-
- nglyphs_before = it->glyph_row->used[TEXT_AREA];
- nwritten = display_string (spec, Qnil, elt,
- charpos, 0, it,
- field, prec, 0,
- multibyte);
-
- /* Assign to the glyphs written above the
- string where the `%x' came from, position
- of the `%'. */
- if (nwritten > 0)
- {
- struct glyph *glyph
- = (it->glyph_row->glyphs[TEXT_AREA]
- + nglyphs_before);
- int i;
-
- for (i = 0; i < nwritten; ++i)
- {
- glyph[i].object = elt;
- glyph[i].charpos = charpos;
- }
-
- n += nwritten;
- }
+ case MODE_LINE_NOPROP:
+ case MODE_LINE_TITLE:
+ n += store_mode_line_noprop (spec, field, prec);
+ break;
+ case MODE_LINE_STRING:
+ {
+ int len = strlen (spec);
+ Lisp_Object tem = 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);
+ }
+ break;
+ case MODE_LINE_DISPLAY:
+ {
+ int nglyphs_before, nwritten;
+
+ nglyphs_before = it->glyph_row->used[TEXT_AREA];
+ nwritten = display_string (spec, Qnil, elt,
+ charpos, 0, it,
+ field, prec, 0,
+ multibyte);
+
+ /* Assign to the glyphs written above the
+ string where the `%x' came from, position
+ of the `%'. */
+ if (nwritten > 0)
+ {
+ struct glyph *glyph
+ = (it->glyph_row->glyphs[TEXT_AREA]
+ + nglyphs_before);
+ int i;
+
+ for (i = 0; i < nwritten; ++i)
+ {
+ glyph[i].object = elt;
+ glyph[i].charpos = charpos;
+ }
+
+ n += nwritten;
+ }
+ }
+ break;
}
}
else /* c == 0 */
&& --limit > 0
&& (precision <= 0 || n < precision))
{
- n += display_mode_element (it, depth, field_width - n,
+ n += display_mode_element (it, depth,
+ /* Do padding only after the last
+ element in the list. */
+ (! CONSP (XCDR (elt))
+ ? field_width - n
+ : 0),
precision - n, XCAR (elt),
props, risky);
elt = XCDR (elt);
/* Pad to FIELD_WIDTH. */
if (field_width > 0 && n < field_width)
{
- if (frame_title_ptr)
- n += store_frame_title ("", field_width - n, 0);
- else if (!NILP (mode_line_string_list))
- n += store_mode_line_string ("", Qnil, 0, field_width - n, 0, Qnil);
- else
- n += display_string ("", Qnil, Qnil, 0, 0, it, field_width - n,
- 0, 0, 0);
+ switch (mode_line_target)
+ {
+ case MODE_LINE_NOPROP:
+ case MODE_LINE_TITLE:
+ n += store_mode_line_noprop ("", field_width - n, 0);
+ break;
+ case MODE_LINE_STRING:
+ n += store_mode_line_string ("", Qnil, 0, field_width - n, 0, Qnil);
+ break;
+ case MODE_LINE_DISPLAY:
+ n += display_string ("", Qnil, Qnil, 0, 0, it, field_width - n,
+ 0, 0, 0);
+ break;
+ }
}
return n;
props = mode_line_string_face_prop;
else if (!NILP (mode_line_string_face))
{
- Lisp_Object face = Fsafe_plist_get (props, Qface);
+ Lisp_Object face = Fplist_get (props, Qface);
props = Fcopy_sequence (props);
if (NILP (face))
face = mode_line_string_face;
Lisp_Object face;
if (NILP (props))
props = Ftext_properties_at (make_number (0), lisp_string);
- face = Fsafe_plist_get (props, Qface);
+ face = Fplist_get (props, Qface);
if (NILP (face))
face = mode_line_string_face;
else
struct buffer *old_buffer = NULL;
int face_id = -1;
int no_props = INTEGERP (face);
+ int count = SPECPDL_INDEX ();
+ Lisp_Object str;
+ int string_start = 0;
if (NILP (window))
window = selected_window;
face_id = DEFAULT_FACE_ID;
if (XBUFFER (buffer) != current_buffer)
- {
- old_buffer = current_buffer;
- set_buffer_internal_1 (XBUFFER (buffer));
- }
+ old_buffer = current_buffer;
+
+ /* Save things including mode_line_proptrans_alist,
+ and set that to nil so that we don't alter the outer value. */
+ record_unwind_protect (unwind_format_mode_line,
+ format_mode_line_unwind_data (old_buffer, 1));
+ mode_line_proptrans_alist = Qnil;
+
+ if (old_buffer)
+ set_buffer_internal_1 (XBUFFER (buffer));
init_iterator (&it, w, -1, -1, NULL, face_id);
- if (!no_props)
+ if (no_props)
{
- mode_line_string_face = face;
- mode_line_string_face_prop
- = (NILP (face) ? Qnil : Fcons (Qface, Fcons (face, Qnil)));
-
- /* We need a dummy last element in mode_line_string_list to
- indicate we are building the propertized mode-line string.
- Using mode_line_string_face_prop here GC protects it. */
- mode_line_string_list
- = Fcons (mode_line_string_face_prop, Qnil);
- frame_title_ptr = NULL;
+ mode_line_target = MODE_LINE_NOPROP;
+ mode_line_string_face_prop = Qnil;
+ mode_line_string_list = Qnil;
+ string_start = MODE_LINE_NOPROP_LEN (0);
}
else
{
- mode_line_string_face_prop = Qnil;
+ mode_line_target = MODE_LINE_STRING;
mode_line_string_list = Qnil;
- frame_title_ptr = frame_title_buf;
+ mode_line_string_face = face;
+ mode_line_string_face_prop
+ = (NILP (face) ? Qnil : Fcons (Qface, Fcons (face, Qnil)));
}
push_frame_kboard (it.f);
display_mode_element (&it, 0, 0, 0, format, Qnil, 0);
pop_frame_kboard ();
- if (old_buffer)
- set_buffer_internal_1 (old_buffer);
-
- if (!no_props)
+ if (no_props)
{
- Lisp_Object str;
- mode_line_string_list = Fnreverse (mode_line_string_list);
- str = Fmapconcat (intern ("identity"), XCDR (mode_line_string_list),
- make_string ("", 0));
- mode_line_string_face_prop = Qnil;
- mode_line_string_list = Qnil;
- return str;
+ len = MODE_LINE_NOPROP_LEN (string_start);
+ str = make_string (mode_line_noprop_buf + string_start, len);
}
-
- len = frame_title_ptr - frame_title_buf;
- if (len > 0 && frame_title_ptr[-1] == '-')
+ else
{
- /* Mode lines typically ends with numerous dashes; reduce to two dashes. */
- while (frame_title_ptr > frame_title_buf && *--frame_title_ptr == '-')
- ;
- frame_title_ptr += 3; /* restore last non-dash + two dashes */
- if (len > frame_title_ptr - frame_title_buf)
- len = frame_title_ptr - frame_title_buf;
+ mode_line_string_list = Fnreverse (mode_line_string_list);
+ str = Fmapconcat (intern ("identity"), mode_line_string_list,
+ make_string ("", 0));
}
- frame_title_ptr = NULL;
- return make_string (frame_title_buf, len);
+ unbind_to (count, Qnil);
+ return str;
}
/* Write a null-terminated, right justified decimal representation of
register int i;
/* Let lots_of_dashes be a string of infinite length. */
- if (!NILP (mode_line_string_list))
+ if (mode_line_target == MODE_LINE_NOPROP ||
+ mode_line_target == MODE_LINE_STRING)
return "--";
if (field_width <= 0
|| field_width > sizeof (lots_of_dashes))
return decode_mode_spec_buf;
}
+ case 'e':
+#ifndef SYSTEM_MALLOC
+ {
+ if (NILP (Vmemory_full))
+ return "";
+ else
+ return "!MEM FULL! ";
+ }
+#else
+ return "";
+#endif
+
case 'F':
/* %F displays the frame name. */
if (!NILP (f->title))
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,
if (pixels > 0)
{
double ppi;
+#ifdef HAVE_WINDOW_SYSTEM
+ if (FRAME_WINDOW_P (it->f)
+ && (ppi = (width_p
+ ? FRAME_X_DISPLAY_INFO (it->f)->resx
+ : FRAME_X_DISPLAY_INFO (it->f)->resy),
+ ppi > 0))
+ return OK_PIXELS (ppi / pixels);
+#endif
+
if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0)
|| (CONSP (Vdisplay_pixels_per_inch)
&& (ppi = (width_p
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);
FACES is an array of faces for all components of this composition.
S->gidx is the index of the first component for S.
- OVERLAPS_P non-zero means S should draw the foreground only, and
- use its physical height for clipping.
+
+ OVERLAPS non-zero means S should draw the foreground only, and use
+ its physical height for clipping. See also draw_glyphs.
Value is the index of a component not in S. */
static int
-fill_composite_glyph_string (s, faces, overlaps_p)
+fill_composite_glyph_string (s, faces, overlaps)
struct glyph_string *s;
struct face **faces;
- int overlaps_p;
+ int overlaps;
{
int i;
xassert (s);
- s->for_overlaps_p = overlaps_p;
+ s->for_overlaps = overlaps;
s->face = faces[s->gidx];
s->font = s->face->font;
FACE_ID is the face id of the string. START is the index of the
first glyph to consider, END is the index of the last + 1.
- OVERLAPS_P non-zero means S should draw the foreground only, and
- use its physical height for clipping.
+ OVERLAPS non-zero means S should draw the foreground only, and use
+ its physical height for clipping. See also draw_glyphs.
Value is the index of the first glyph not in S. */
static int
-fill_glyph_string (s, face_id, start, end, overlaps_p)
+fill_glyph_string (s, face_id, start, end, overlaps)
struct glyph_string *s;
int face_id;
- int start, end, overlaps_p;
+ int start, end, overlaps;
{
struct glyph *glyph, *last;
int voffset;
xassert (s->nchars == 0);
xassert (start >= 0 && end > start);
- s->for_overlaps_p = overlaps_p,
+ s->for_overlaps = overlaps,
glyph = s->row->glyphs[s->area] + start;
last = s->row->glyphs[s->area] + end;
voffset = glyph->voffset;
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);
{
/* If the face of this glyph string has to be drawn to the end of
the drawing area, set S->extends_to_end_of_line_p. */
- struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
if (start == s->row->used[s->area]
&& s->area == TEXT_AREA
- && ((s->hl == DRAW_NORMAL_TEXT
- && (s->row->fill_line_p
- || s->face->background != default_face->background
- || s->face->stipple != default_face->stipple
- || s->row->mouse_face_p))
- || s->hl == DRAW_MOUSE_FACE
- || ((s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN)
- && s->row->fill_line_p)))
- s->extends_to_end_of_line_p = 1;
+ && ((s->row->fill_line_p
+ && (s->hl == DRAW_NORMAL_TEXT
+ || s->hl == DRAW_IMAGE_RAISED
+ || s->hl == DRAW_IMAGE_SUNKEN))
+ || s->hl == DRAW_MOUSE_FACE))
+ s->extends_to_end_of_line_p = 1;
/* If S extends its face to the end of the line, set its
background_width to the distance to the right edge of the drawing
INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL); \
append_glyph_string (&HEAD, &TAIL, s); \
s->x = (X); \
- START = fill_glyph_string (s, face_id, START, END, overlaps_p); \
+ START = fill_glyph_string (s, face_id, START, END, overlaps); \
} \
while (0)
if (n == 0) \
first_s = s; \
\
- n = fill_composite_glyph_string (s, faces, overlaps_p); \
+ n = fill_composite_glyph_string (s, faces, overlaps); \
} \
\
++START; \
DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
DRAW_IMAGE_RAISED draw an image with a raised relief around it
- If OVERLAPS_P is non-zero, draw only the foreground of characters
- and clip to the physical height of ROW.
+ If OVERLAPS is non-zero, draw only the foreground of characters and
+ clip to the physical height of ROW. Non-zero value also defines
+ the overlapping part to be drawn:
+
+ OVERLAPS_PRED overlap with preceding rows
+ OVERLAPS_SUCC overlap with succeeding rows
+ OVERLAPS_BOTH overlap with both preceding/succeeding rows
+ OVERLAPS_ERASED_CURSOR overlap with erased cursor area
Value is the x-position reached, relative to AREA of W. */
static int
-draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
+draw_glyphs (w, x, row, area, start, end, hl, overlaps)
struct window *w;
int x;
struct glyph_row *row;
enum glyph_row_area area;
int start, end;
enum draw_glyphs_face hl;
- int overlaps_p;
+ int overlaps;
{
struct glyph_string *head, *tail;
struct glyph_string *s;
/* If there are any glyphs with lbearing < 0 or rbearing > width in
the row, redraw some glyphs in front or following the glyph
strings built above. */
- if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
+ if (head && !overlaps && row->contains_overlapping_glyphs_p)
{
int dummy_x = 0;
struct glyph_string *h, *t;
/* When drawing overlapping rows, only the glyph strings'
foreground is drawn, which doesn't erase a cursor
completely. */
- && !overlaps_p)
+ && !overlaps)
{
int x0 = clip_head ? clip_head->x : (head ? head->x : x);
int x1 = (clip_tail ? clip_tail->x + clip_tail->background_width
{
struct image *img;
struct face *face;
- int glyph_ascent;
+ int glyph_ascent, crop;
struct glyph_slice slice;
xassert (it->what == IT_IMAGE);
take_vertical_position_into_account (it);
+ /* Automatically crop wide image glyphs at right edge so we can
+ draw the cursor on same display row. */
+ if ((crop = it->pixel_width - (it->last_visible_x - it->current_x), crop > 0)
+ && (it->hpos == 0 || it->pixel_width > it->last_visible_x / 4))
+ {
+ it->pixel_width -= crop;
+ slice.width -= crop;
+ }
+
if (it->glyph_row)
{
struct glyph *glyph;
plist = XCDR (it->object);
/* Compute the width of the stretch. */
- if ((prop = Fsafe_plist_get (plist, QCwidth), !NILP (prop))
+ if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
&& calc_pixel_width_or_height (&tem, it, prop, font, 1, 0))
{
/* Absolute width `:width WIDTH' specified and valid. */
zero_width_ok_p = 1;
width = (int)tem;
}
- else if (prop = Fsafe_plist_get (plist, QCrelative_width),
+ else if (prop = Fplist_get (plist, QCrelative_width),
NUMVAL (prop) > 0)
{
/* Relative width `:relative-width FACTOR' specified and valid.
x_produce_glyphs (&it2);
width = NUMVAL (prop) * it2.pixel_width;
}
- else if ((prop = Fsafe_plist_get (plist, QCalign_to), !NILP (prop))
+ else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
&& calc_pixel_width_or_height (&tem, it, prop, font, 1, &align_to))
{
if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
width = 1;
/* Compute height. */
- if ((prop = Fsafe_plist_get (plist, QCheight), !NILP (prop))
+ if ((prop = Fplist_get (plist, QCheight), !NILP (prop))
&& calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
{
height = (int)tem;
zero_height_ok_p = 1;
}
- else if (prop = Fsafe_plist_get (plist, QCrelative_height),
+ else if (prop = Fplist_get (plist, QCrelative_height),
NUMVAL (prop) > 0)
height = FONT_HEIGHT (font) * NUMVAL (prop);
else
/* Compute percentage of height used for ascent. If
`:ascent ASCENT' is present and valid, use that. Otherwise,
derive the ascent from the font in use. */
- if (prop = Fsafe_plist_get (plist, QCascent),
+ if (prop = Fplist_get (plist, QCascent),
NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
ascent = height * NUMVAL (prop) / 100.0;
else if (!NILP (prop)
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);
}
struct it *it;
Lisp_Object prop;
{
- Lisp_Object position, val;
+ Lisp_Object position;
if (STRINGP (it->object))
position = make_number (IT_STRING_CHARPOS (*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)
/* If face has an overline, add the height of the overline
(1 pixel) and a 1 pixel margin to the character height. */
if (face->overline_p)
- it->ascent += 2;
+ it->ascent += overline_margin;
if (it->constrain_row_ascent_descent_p)
{
else
{
Lisp_Object spacing;
- int total = 0;
it->phys_ascent = it->ascent;
it->phys_descent = it->descent;
/* If face has an overline, add the height of the overline
(1 pixel) and a 1 pixel margin to the character height. */
if (face->overline_p)
- it->ascent += 2;
+ it->ascent += overline_margin;
take_vertical_position_into_account (it);
/* If face has an overline, add the height of the overline
(1 pixel) and a 1 pixel margin to the character height. */
if (face->overline_p)
- it->ascent += 2;
+ it->ascent += overline_margin;
take_vertical_position_into_account (it);
{
if (w == XWINDOW (echo_area_window))
{
- *width = FRAME_CURSOR_WIDTH (f);
- return FRAME_DESIRED_CURSOR (f);
+ if (EQ (b->cursor_type, Qt) || NILP (b->cursor_type))
+ {
+ *width = FRAME_CURSOR_WIDTH (f);
+ return FRAME_DESIRED_CURSOR (f);
+ }
+ else
+ return get_specified_cursor_type (b->cursor_type, width);
}
*active_cursor = 0;
/* Use cursor-in-non-selected-windows for non-selected window or frame. */
if (non_selected)
{
- alt_cursor = Fbuffer_local_value (Qcursor_in_non_selected_windows, w->buffer);
+ alt_cursor = b->cursor_in_non_selected_windows;
return get_specified_cursor_type (alt_cursor, width);
}
/* Use normal cursor if not blinked off. */
if (!w->cursor_off_p)
{
- if (glyph != NULL && glyph->type == IMAGE_GLYPH) {
- if (cursor_type == FILLED_BOX_CURSOR)
- cursor_type = HOLLOW_BOX_CURSOR;
+#ifdef HAVE_WINDOW_SYSTEM
+ if (glyph != NULL && glyph->type == IMAGE_GLYPH)
+ {
+ if (cursor_type == FILLED_BOX_CURSOR)
+ {
+ /* Using a block cursor on large images can be very annoying.
+ So use a hollow cursor for "large" images.
+ If image is not transparent (no mask), also use hollow cursor. */
+ struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id);
+ if (img != NULL && IMAGEP (img->spec))
+ {
+ /* Arbitrarily, interpret "Large" as >32x32 and >NxN
+ where N = size of default frame font size.
+ This should cover most of the "tiny" icons people may use. */
+ if (!img->mask
+ || img->width > max (32, WINDOW_FRAME_COLUMN_WIDTH (w))
+ || img->height > max (32, WINDOW_FRAME_LINE_HEIGHT (w)))
+ cursor_type = HOLLOW_BOX_CURSOR;
+ }
+ }
+ else if (cursor_type != NO_CURSOR)
+ {
+ /* Display current only supports BOX and HOLLOW cursors for images.
+ So for now, unconditionally use a HOLLOW cursor when cursor is
+ not a solid box cursor. */
+ cursor_type = HOLLOW_BOX_CURSOR;
+ }
}
+#endif
return cursor_type;
}
if (area != TEXT_AREA)
return;
- row = w->current_matrix->rows + w->phys_cursor.vpos;
- if (!row->displays_text_p)
+ if (w->phys_cursor.vpos < 0
+ || w->phys_cursor.vpos >= w->current_matrix->nrows
+ || (row = w->current_matrix->rows + w->phys_cursor.vpos,
+ !(row->enabled_p && row->displays_text_p)))
return;
if (row->cursor_in_fringe_p)
#ifdef HAVE_WINDOW_SYSTEM
/* EXPORT for RIF:
- Fix the display of area AREA of overlapping row ROW in window W. */
+ Fix the display of area AREA of overlapping row ROW in window W
+ with respect to the overlapping part OVERLAPS. */
void
-x_fix_overlapping_area (w, row, area)
+x_fix_overlapping_area (w, row, area, overlaps)
struct window *w;
struct glyph_row *row;
enum glyph_row_area area;
+ int overlaps;
{
int i, x;
draw_glyphs (w, start_x, row, area,
start, i,
- DRAW_NORMAL_TEXT, 1);
+ DRAW_NORMAL_TEXT, overlaps);
}
else
{
are redrawn. */
else if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
{
+ w->phys_cursor_width = x1 - w->phys_cursor.x;
+
if (row > w->current_matrix->rows
&& MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
- x_fix_overlapping_area (w, row - 1, TEXT_AREA);
+ x_fix_overlapping_area (w, row - 1, TEXT_AREA,
+ OVERLAPS_ERASED_CURSOR);
if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
&& MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
- x_fix_overlapping_area (w, row + 1, TEXT_AREA);
+ x_fix_overlapping_area (w, row + 1, TEXT_AREA,
+ OVERLAPS_ERASED_CURSOR);
}
}
}
/* 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 (row == last)
end_hpos = dpyinfo->mouse_face_end_col;
else
- end_hpos = row->used[TEXT_AREA];
+ {
+ end_hpos = row->used[TEXT_AREA];
+ if (draw == DRAW_NORMAL_TEXT)
+ row->fill_line_p = 1; /* Clear to end of line */
+ }
if (end_hpos > start_hpos)
{
/* If whole rows or last part of a row came from a display overlay,
row_containing_pos will skip over such rows because their end pos
- equals the start pos of the overlay or interval. Backtrack if we
- have a STOP object and previous row's end glyph came from STOP. */
+ equals the start pos of the overlay or interval.
+
+ Move back if we have a STOP object and previous row's
+ end glyph came from STOP. */
if (!NILP (stop))
{
- struct glyph_row *prev = row-1;
+ struct glyph_row *prev;
while ((prev = row - 1, prev >= first)
&& MATRIX_ROW_END_CHARPOS (prev) == charpos
&& prev->used[TEXT_AREA] > 0)
{
- end = prev->glyphs[TEXT_AREA];
- glyph = end + prev->used[TEXT_AREA];
- while (--glyph >= end
+ struct glyph *beg = prev->glyphs[TEXT_AREA];
+ glyph = beg + prev->used[TEXT_AREA];
+ while (--glyph >= beg
&& INTEGERP (glyph->object));
- if (glyph >= end
- && !EQ (stop, glyph->object))
+ if (glyph < beg
+ || !EQ (stop, glyph->object))
break;
row = prev;
}
position relative to the start of the mode line. */
static void
-note_mode_line_or_margin_highlight (w, x, y, area)
- struct window *w;
+note_mode_line_or_margin_highlight (window, x, y, area)
+ Lisp_Object window;
int x, y;
enum window_part area;
{
+ struct window *w = XWINDOW (window);
struct frame *f = XFRAME (w->frame);
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
Cursor cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
Lisp_Object string, object = Qnil;
Lisp_Object pos, help;
+ Lisp_Object mouse_face;
+ int original_x_pixel = x;
+ struct glyph * glyph = NULL;
+ struct glyph_row *row;
+
if (area == ON_MODE_LINE || area == ON_HEADER_LINE)
- string = mode_line_string (w, area, &x, &y, &charpos,
- &object, &dx, &dy, &width, &height);
+ {
+ int x0;
+ struct glyph *end;
+
+ string = mode_line_string (w, area, &x, &y, &charpos,
+ &object, &dx, &dy, &width, &height);
+
+ row = (area == ON_MODE_LINE
+ ? MATRIX_MODE_LINE_ROW (w->current_matrix)
+ : MATRIX_HEADER_LINE_ROW (w->current_matrix));
+
+ /* Find glyph */
+ if (row->mode_line_p && row->enabled_p)
+ {
+ glyph = row->glyphs[TEXT_AREA];
+ end = glyph + row->used[TEXT_AREA];
+
+ for (x0 = original_x_pixel;
+ glyph < end && x0 >= glyph->pixel_width;
+ ++glyph)
+ x0 -= glyph->pixel_width;
+
+ if (glyph >= end)
+ glyph = NULL;
+ }
+ }
else
{
x -= WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w);
if (IMAGEP (object))
{
Lisp_Object image_map, hotspot;
- if ((image_map = Fsafe_plist_get (XCDR (object), QCmap),
+ if ((image_map = Fplist_get (XCDR (object), QCmap),
!NILP (image_map))
&& (hotspot = find_hot_spot (image_map, dx, dy),
CONSP (hotspot))
if (CONSP (hotspot)
&& (plist = XCAR (hotspot), CONSP (plist)))
{
- pointer = Fsafe_plist_get (plist, Qpointer);
+ pointer = Fplist_get (plist, Qpointer);
if (NILP (pointer))
pointer = Qhand;
- help = Fsafe_plist_get (plist, Qhelp_echo);
+ help = Fplist_get (plist, Qhelp_echo);
if (!NILP (help))
{
help_echo_string = help;
}
}
if (NILP (pointer))
- pointer = Fsafe_plist_get (XCDR (object), QCpointer);
+ pointer = Fplist_get (XCDR (object), QCpointer);
}
if (STRINGP (string))
if (!KEYMAPP (map))
cursor = dpyinfo->vertical_scroll_bar_cursor;
}
- }
+ /* Change the mouse face according to what is under X/Y. */
+ mouse_face = Fget_text_property (pos, Qmouse_face, string);
+ if (!NILP (mouse_face)
+ && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))
+ && glyph)
+ {
+ Lisp_Object b, e;
+
+ struct glyph * tmp_glyph;
+
+ int gpos;
+ int gseq_length;
+ int total_pixel_width;
+ int ignore;
+
+ int vpos, hpos;
+
+ b = Fprevious_single_property_change (make_number (charpos + 1),
+ Qmouse_face, string, Qnil);
+ if (NILP (b))
+ b = make_number (0);
+
+ e = Fnext_single_property_change (pos, Qmouse_face, string, Qnil);
+ if (NILP (e))
+ e = make_number (SCHARS (string));
+
+ /* Calculate the position(glyph position: GPOS) of GLYPH in
+ displayed string. GPOS is different from CHARPOS.
+
+ CHARPOS is the position of glyph in internal string
+ object. A mode line string format has structures which
+ is converted to a flatten by emacs lisp interpreter.
+ The internal string is an element of the structures.
+ The displayed string is the flatten string. */
+ for (tmp_glyph = glyph - 1, gpos = 0;
+ tmp_glyph->charpos >= XINT (b);
+ tmp_glyph--, gpos++)
+ {
+ if (!EQ (tmp_glyph->object, glyph->object))
+ break;
+ }
+
+ /* Calculate the lenght(glyph sequence length: GSEQ_LENGTH) of
+ displayed string holding GLYPH.
+
+ GSEQ_LENGTH is different from SCHARS (STRING).
+ SCHARS (STRING) returns the length of the internal string. */
+ for (tmp_glyph = glyph, gseq_length = gpos;
+ tmp_glyph->charpos < XINT (e);
+ tmp_glyph++, gseq_length++)
+ {
+ if (!EQ (tmp_glyph->object, glyph->object))
+ break;
+ }
+
+ total_pixel_width = 0;
+ for (tmp_glyph = glyph - gpos; tmp_glyph != glyph; tmp_glyph++)
+ total_pixel_width += tmp_glyph->pixel_width;
+
+ /* Pre calculation of re-rendering position */
+ vpos = (x - gpos);
+ hpos = (area == ON_MODE_LINE
+ ? (w->current_matrix)->nrows - 1
+ : 0);
+
+ /* If the re-rendering position is included in the last
+ re-rendering area, we should do nothing. */
+ if ( EQ (window, dpyinfo->mouse_face_window)
+ && dpyinfo->mouse_face_beg_col <= vpos
+ && vpos < dpyinfo->mouse_face_end_col
+ && dpyinfo->mouse_face_beg_row == hpos )
+ return;
+
+ if (clear_mouse_face (dpyinfo))
+ cursor = No_Cursor;
+
+ dpyinfo->mouse_face_beg_col = vpos;
+ dpyinfo->mouse_face_beg_row = hpos;
+
+ dpyinfo->mouse_face_beg_x = original_x_pixel - (total_pixel_width + dx);
+ dpyinfo->mouse_face_beg_y = 0;
+
+ dpyinfo->mouse_face_end_col = vpos + gseq_length;
+ dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_beg_row;
+
+ dpyinfo->mouse_face_end_x = 0;
+ dpyinfo->mouse_face_end_y = 0;
+
+ dpyinfo->mouse_face_past_end = 0;
+ dpyinfo->mouse_face_window = window;
+
+ dpyinfo->mouse_face_face_id = face_at_string_position (w, string,
+ charpos,
+ 0, 0, 0, &ignore,
+ glyph->face_id, 1);
+ show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+
+ if (NILP (pointer))
+ pointer = Qhand;
+ }
+ else if ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))
+ clear_mouse_face (dpyinfo);
+ }
define_frame_cursor1 (f, cursor, pointer);
}
/* If we were displaying active text in another window, clear that.
Also clear if we move out of text area in same window. */
if (! EQ (window, dpyinfo->mouse_face_window)
- || (part != ON_TEXT && !NILP (dpyinfo->mouse_face_window)))
+ || (part != ON_TEXT && part != ON_MODE_LINE && part != ON_HEADER_LINE
+ && !NILP (dpyinfo->mouse_face_window)))
clear_mouse_face (dpyinfo);
/* Not on a window -> return. */
if (part == ON_MODE_LINE || part == ON_HEADER_LINE
|| part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
{
- note_mode_line_or_margin_highlight (w, x, y, part);
+ note_mode_line_or_margin_highlight (window, x, y, part);
return;
}
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;
if (img != NULL && IMAGEP (img->spec))
{
Lisp_Object image_map, hotspot;
- if ((image_map = Fsafe_plist_get (XCDR (img->spec), QCmap),
+ if ((image_map = Fplist_get (XCDR (img->spec), QCmap),
!NILP (image_map))
&& (hotspot = find_hot_spot (image_map,
glyph->slice.x + dx,
if (CONSP (hotspot)
&& (plist = XCAR (hotspot), CONSP (plist)))
{
- pointer = Fsafe_plist_get (plist, Qpointer);
+ pointer = Fplist_get (plist, Qpointer);
if (NILP (pointer))
pointer = Qhand;
- help_echo_string = Fsafe_plist_get (plist, Qhelp_echo);
+ help_echo_string = Fplist_get (plist, Qhelp_echo);
if (!NILP (help_echo_string))
{
help_echo_window = window;
}
}
if (NILP (pointer))
- pointer = Fsafe_plist_get (XCDR (img->spec), QCpointer);
+ pointer = Fplist_get (XCDR (img->spec), QCpointer);
}
}
b = make_number (0);
if (NILP (e))
e = make_number (SCHARS (object) - 1);
+
fast_find_string_pos (w, XINT (b), object,
&dpyinfo->mouse_face_beg_col,
&dpyinfo->mouse_face_beg_row,
xassert (row->enabled_p && !row->mode_line_p);
if (row->used[LEFT_MARGIN_AREA])
- x_fix_overlapping_area (w, row, LEFT_MARGIN_AREA);
+ x_fix_overlapping_area (w, row, LEFT_MARGIN_AREA, OVERLAPS_BOTH);
if (row->used[TEXT_AREA])
- x_fix_overlapping_area (w, row, TEXT_AREA);
+ x_fix_overlapping_area (w, row, TEXT_AREA, OVERLAPS_BOTH);
if (row->used[RIGHT_MARGIN_AREA])
- x_fix_overlapping_area (w, row, RIGHT_MARGIN_AREA);
+ x_fix_overlapping_area (w, row, RIGHT_MARGIN_AREA, OVERLAPS_BOTH);
}
}
window_box_edges (w, -1, &x0, &y0, &x1, &y1);
y1 -= 1;
+ if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
+ x1 -= 1;
+
rif->draw_vertical_window_border (w, x1, y0, y1);
}
else if (!WINDOW_LEFTMOST_P (w)
window_box_edges (w, -1, &x0, &y0, &x1, &y1);
y1 -= 1;
+ if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
+ x0 -= 1;
+
rif->draw_vertical_window_border (w, x0, y0, y1);
}
}
staticpro (&Qtrailing_whitespace);
Qescape_glyph = intern ("escape-glyph");
staticpro (&Qescape_glyph);
+ Qnobreak_space = intern ("nobreak-space");
+ staticpro (&Qnobreak_space);
Qimage = intern ("image");
staticpro (&Qimage);
QCmap = intern (":map");
staticpro (&Qpoly);
Qmessage_truncate_lines = intern ("message-truncate-lines");
staticpro (&Qmessage_truncate_lines);
- Qcursor_in_non_selected_windows = intern ("cursor-in-non-selected-windows");
- staticpro (&Qcursor_in_non_selected_windows);
Qgrow_only = intern ("grow-only");
staticpro (&Qgrow_only);
Qinhibit_menubar_update = intern ("inhibit-menubar-update");
mode_line_proptrans_alist = Qnil;
staticpro (&mode_line_proptrans_alist);
-
mode_line_string_list = Qnil;
staticpro (&mode_line_string_list);
+ mode_line_string_face = Qnil;
+ staticpro (&mode_line_string_face);
+ mode_line_string_face_prop = Qnil;
+ staticpro (&mode_line_string_face_prop);
+ Vmode_line_unwind_vector = Qnil;
+ staticpro (&Vmode_line_unwind_vector);
help_echo_string = Qnil;
staticpro (&help_echo_string);
The face used for trailing whitespace is `trailing-whitespace'. */);
Vshow_trailing_whitespace = Qnil;
- DEFVAR_LISP ("show-nonbreak-escape", &Vshow_nonbreak_escape,
- doc: /* *Non-nil means display escape character before non-break space and hyphen. */);
- Vshow_nonbreak_escape = Qt;
+ DEFVAR_LISP ("nobreak-char-display", &Vnobreak_char_display,
+ doc: /* *Control highlighting of nobreak space and soft hyphen.
+A value of t means highlight the character itself (for nobreak space,
+use face `nobreak-space').
+A value of nil means no highlighting.
+Other values mean display the escape glyph followed by an ordinary
+space or ordinary hyphen. */);
+ Vnobreak_char_display = Qt;
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'. */);
+A value of nil means to show the text pointer. Other options are `arrow',
+`text', `hand', `vdrag', `hdrag', `modeline', and `hourglass'. */);
Vvoid_text_area_pointer = Qarrow;
DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay,
DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
doc: /* String to display as an arrow in non-window frames.
See also `overlay-arrow-position'. */);
- Voverlay_arrow_string = Qnil;
+ Voverlay_arrow_string = build_string ("=>");
DEFVAR_LISP ("overlay-arrow-variable-list", &Voverlay_arrow_variable_list,
doc: /* List of variables (symbols) which hold markers for overlay arrows.
scroll_margin = 0;
DEFVAR_LISP ("display-pixels-per-inch", &Vdisplay_pixels_per_inch,
- doc: /* Pixels per inch on current display.
+ doc: /* Pixels per inch value for non-window system displays.
Value is a number or a cons (WIDTH-DPI . HEIGHT-DPI). */);
Vdisplay_pixels_per_inch = make_float (72.0);
is not valid when these functions are called. */);
Vwindow_scroll_functions = Qnil;
- DEFVAR_BOOL ("mouse-autoselect-window", &mouse_autoselect_window,
- doc: /* *Non-nil means autoselect window with mouse pointer. */);
- mouse_autoselect_window = 0;
+ 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.
+See `set-window-redisplay-end-trigger'. */);
+ Vredisplay_end_trigger_functions = Qnil;
+
+ DEFVAR_LISP ("mouse-autoselect-window", &Vmouse_autoselect_window,
+ doc: /* *Non-nil means autoselect window with mouse pointer.
+If nil, do not autoselect windows.
+A positive number means delay autoselection by that many seconds: a
+window is autoselected only after the mouse has remained in that
+window for the duration of the delay.
+A negative number has a similar effect, but causes windows to be
+autoselected only after the mouse has stopped moving. \(Because of
+the way Emacs compares mouse events, you will occasionally wait twice
+that time before the window gets selected.\)
+Any other value means to autoselect window instantaneously when the
+mouse pointer enters it.
+
+Autoselection selects the minibuffer only if it is active, and never
+unselects the minibuffer if it is active. */);
+ Vmouse_autoselect_window = Qnil;
DEFVAR_BOOL ("auto-resize-tool-bars", &auto_resize_tool_bars_p,
doc: /* *Non-nil means automatically resize tool-bars.
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.
go back to their normal size. */);
Vresize_mini_windows = Qgrow_only;
- DEFVAR_LISP ("cursor-in-non-selected-windows",
- &Vcursor_in_non_selected_windows,
- doc: /* *Cursor type to display in non-selected windows.
-t means to use hollow box cursor. See `cursor-type' for other values. */);
- Vcursor_in_non_selected_windows = Qt;
-
DEFVAR_LISP ("blink-cursor-alist", &Vblink_cursor_alist,
doc: /* Alist specifying how to blink the cursor off.
Each element has the form (ON-STATE . OFF-STATE). Whenever the
`cursor-type' frame-parameter or variable equals ON-STATE,
comparing using `equal', Emacs uses OFF-STATE to specify
-how to blink it off. */);
+how to blink it off. ON-STATE and OFF-STATE are values for
+the `cursor-type' frame parameter.
+
+If a frame's ON-STATE has no entry in this list,
+the frame's other specifications determine how to blink the cursor off. */);
Vblink_cursor_alist = Qnil;
DEFVAR_BOOL ("auto-hscroll-mode", &automatic_hscrolling_p,
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
message_truncate_lines = 0;
DEFVAR_LISP ("menu-bar-update-hook", &Vmenu_bar_update_hook,
- doc: /* Normal hook run for clicks on menu bar, before displaying a submenu.
-Can be used to update submenus whose contents should vary. */);
+ doc: /* Normal hook run to update the menu bar definitions.
+Redisplay runs this hook before it redisplays the menu bar.
+This is used to update submenus such as Buffers,
+whose contents depend on various data. */);
Vmenu_bar_update_hook = Qnil;
+ DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame,
+ doc: /* Frame for which we are updating a menu.
+The enable predicate for a menu binding should check this variable. */);
+ Vmenu_updating_frame = Qnil;
+
DEFVAR_BOOL ("inhibit-menubar-update", &inhibit_menubar_update,
doc: /* Non-nil means don't update menu bars. Internal use only. */);
inhibit_menubar_update = 0;
doc: /* Inhibit try_cursor_movement display optimization. */);
inhibit_try_cursor_movement = 0;
#endif /* GLYPH_DEBUG */
+
+ DEFVAR_INT ("overline-margin", &overline_margin,
+ doc: /* *Space between overline and text, in pixels.
+The default value is 2: the height of the overline (1 pixel) plus 1 pixel
+margin to the caracter height. */);
+ overline_margin = 2;
}
/* Allocate the buffer for frame titles.
Also used for `format-mode-line'. */
int size = 100;
- frame_title_buf = (char *) xmalloc (size);
- frame_title_buf_end = frame_title_buf + size;
- frame_title_ptr = NULL;
+ mode_line_noprop_buf = (char *) xmalloc (size);
+ mode_line_noprop_buf_end = mode_line_noprop_buf + size;
+ mode_line_noprop_ptr = mode_line_noprop_buf;
+ mode_line_target = MODE_LINE_DISPLAY;
}
help_echo_showing_p = 0;