#include <config.h>
#include <stdio.h>
#include "lisp.h"
#include "keyboard.h"
#include "frame.h"
#include "window.h"
#include "termchar.h"
#include "dispextern.h"
#include "buffer.h"
#include "charset.h"
#include "indent.h"
#include "commands.h"
#include "macros.h"
#include "disptab.h"
#include "termhooks.h"
#include "intervals.h"
#include "coding.h"
#include "process.h"
#include "region-cache.h"
#include "fontset.h"
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
#ifdef WINDOWSNT
#include "w32term.h"
#endif
#ifdef macintosh
#include "macterm.h"
#endif
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define INFINITY 10000000
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
extern void set_frame_menubar P_ ((struct frame *f, int, int));
extern int pending_menu_activation;
#endif
extern int interrupt_input;
extern int command_loop_level;
extern int minibuffer_auto_raise;
extern Lisp_Object Qface;
extern Lisp_Object Voverriding_local_map;
extern Lisp_Object Voverriding_local_map_menu_flag;
extern Lisp_Object Qmenu_item;
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 Qinhibit_point_motion_hooks;
Lisp_Object QCeval, Qwhen, QCfile, QCdata;
Lisp_Object Qfontified;
Lisp_Object Qgrow_only;
Lisp_Object Qinhibit_eval_during_redisplay;
Lisp_Object Qbuffer_position, Qposition, Qobject;
Lisp_Object Vfontification_functions;
Lisp_Object Qfontification_functions;
int auto_raise_tool_bar_buttons_p;
Lisp_Object Vtool_bar_button_margin;
int tool_bar_button_relief;
int auto_resize_tool_bars_p;
Lisp_Object Vinhibit_redisplay, Qinhibit_redisplay;
int inhibit_eval_during_redisplay;
Lisp_Object Qdisplay, Qrelative_width, Qalign_to;
extern Lisp_Object Qface, Qinvisible, Qimage, Qwidth;
Lisp_Object Qspace, QCalign_to, QCrelative_width, QCrelative_height;
Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise;
Lisp_Object Qmargin;
extern Lisp_Object Qheight;
Lisp_Object Vshow_trailing_whitespace;
Lisp_Object Qtrailing_whitespace;
Lisp_Object Qimage;
int noninteractive_need_newline;
static int message_log_need_newline;
static struct text_pos this_line_start_pos;
static struct text_pos this_line_end_pos;
static int this_line_vpos;
static int this_line_y;
static int this_line_pixel_height;
static int this_line_start_x;
static struct buffer *this_line_buffer;
int truncate_partial_width_windows;
int unibyte_display_via_language_environment;
int multiple_frames;
Lisp_Object Vglobal_mode_string;
Lisp_Object Voverlay_arrow_position;
Lisp_Object Voverlay_arrow_string;
static Lisp_Object last_arrow_position, last_arrow_string;
Lisp_Object Vframe_title_format;
Lisp_Object Vicon_title_format;
static Lisp_Object Vwindow_size_change_functions;
Lisp_Object Qmenu_bar_update_hook, Vmenu_bar_update_hook;
static int overlay_arrow_seen;
int highlight_nonselected_windows;
static int scroll_step;
static int scroll_conservatively;
int scroll_margin;
int buffer_shared;
static Lisp_Object default_invis_vector[3];
int mode_line_inverse_video;
Lisp_Object minibuf_prompt;
int minibuf_prompt_width;
int minibuf_prompt_pixel_width;
Lisp_Object echo_area_window;
Lisp_Object Vmessage_stack;
int message_enable_multibyte;
int update_mode_lines;
int windows_or_buffers_changed;
int line_number_displayed;
Lisp_Object Vline_number_display_limit;
static int line_number_display_limit_width;
Lisp_Object Vmessage_log_max;
static Lisp_Object Vmessages_buffer_name;
Lisp_Object echo_area_buffer[2];
static Lisp_Object echo_buffer[2];
static Lisp_Object Vwith_echo_area_save_vector;
static int display_last_displayed_message_p;
int message_buf_print;
Lisp_Object Qinhibit_menubar_update;
int inhibit_menubar_update;
Lisp_Object Vmax_mini_window_height;
int message_truncate_lines;
Lisp_Object Qmessage_truncate_lines;
static int message_cleared_p;
int cursor_in_non_selected_windows;
#define MAX_SCRATCH_GLYPHS 100
struct glyph_row scratch_glyph_row;
static struct glyph scratch_glyphs[MAX_SCRATCH_GLYPHS];
static int last_max_ascent, last_height;
int help_echo_showing_p;
int current_mode_line_height, current_header_line_height;
#define TEXT_PROP_DISTANCE_LIMIT 100
#if GLYPH_DEBUG
int inhibit_try_window_id, inhibit_try_window_reusing;
int inhibit_try_cursor_movement;
int trace_redisplay_p;
#endif
#ifdef DEBUG_TRACE_MOVE
int trace_move;
#define TRACE_MOVE(x) if (trace_move) fprintf x; else (void) 0
#else
#define TRACE_MOVE(x) (void) 0
#endif
int automatic_hscrolling_p;
Lisp_Object Vimage_types;
Lisp_Object Vresize_mini_windows;
enum prop_handled
{
HANDLED_NORMALLY,
HANDLED_RECOMPUTE_PROPS,
HANDLED_OVERLAY_STRING_CONSUMED,
HANDLED_RETURN
};
struct props
{
Lisp_Object *name;
enum prop_idx idx;
enum prop_handled (*handler) P_ ((struct it *it));
};
static enum prop_handled handle_face_prop P_ ((struct it *));
static enum prop_handled handle_invisible_prop P_ ((struct it *));
static enum prop_handled handle_display_prop P_ ((struct it *));
static enum prop_handled handle_composition_prop P_ ((struct it *));
static enum prop_handled handle_overlay_change P_ ((struct it *));
static enum prop_handled handle_fontified_prop P_ ((struct it *));
static struct props it_props[] =
{
{&Qfontified, FONTIFIED_PROP_IDX, handle_fontified_prop},
{&Qface, FACE_PROP_IDX, handle_face_prop},
{&Qdisplay, DISPLAY_PROP_IDX, handle_display_prop},
{&Qinvisible, INVISIBLE_PROP_IDX, handle_invisible_prop},
{&Qcomposition, COMPOSITION_PROP_IDX, handle_composition_prop},
{NULL, 0, NULL}
};
#define COERCE_MARKER(X) (MARKERP ((X)) ? Fmarker_position (X) : (X))
enum move_it_result
{
MOVE_UNDEFINED,
MOVE_POS_MATCH_OR_ZV,
MOVE_X_REACHED,
MOVE_LINE_CONTINUED,
MOVE_LINE_TRUNCATED,
MOVE_NEWLINE_OR_CR
};
static void setup_for_ellipsis P_ ((struct it *));
static void mark_window_display_accurate_1 P_ ((struct window *, int));
static int single_display_prop_string_p P_ ((Lisp_Object, Lisp_Object));
static int display_prop_string_p P_ ((Lisp_Object, Lisp_Object));
static int cursor_row_p P_ ((struct window *, struct glyph_row *));
static int redisplay_mode_lines P_ ((Lisp_Object, int));
static char *decode_mode_spec_coding P_ ((Lisp_Object, char *, int));
static int invisible_text_between_p P_ ((struct it *, int, int));
static int next_element_from_ellipsis P_ ((struct it *));
static void pint2str P_ ((char *, int, int));
static struct text_pos run_window_scroll_functions P_ ((Lisp_Object,
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_ ((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 single_display_prop_intangible_p P_ ((Lisp_Object));
static void ensure_echo_area_buffers P_ ((void));
static Lisp_Object unwind_with_echo_area_buffer P_ ((Lisp_Object));
static Lisp_Object with_echo_area_buffer_unwind_data P_ ((struct window *));
static int with_echo_area_buffer P_ ((struct window *, int,
int (*) (EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT),
EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
static void clear_garbaged_frames P_ ((void));
static int current_message_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
static int truncate_message_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
static int set_message_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
static int display_echo_area P_ ((struct window *));
static int display_echo_area_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
static int resize_mini_window_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
static Lisp_Object unwind_redisplay P_ ((Lisp_Object));
static int string_char_and_length P_ ((unsigned char *, int, int *));
static struct text_pos display_prop_end P_ ((struct it *, Lisp_Object,
struct text_pos));
static int compute_window_start_on_continuation_line P_ ((struct window *));
static Lisp_Object safe_eval_handler P_ ((Lisp_Object));
static void insert_left_trunc_glyphs P_ ((struct it *));
static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *));
static void extend_face_to_end_of_line P_ ((struct it *));
static int append_space P_ ((struct it *, int));
static int make_cursor_line_fully_visible P_ ((struct window *));
static int try_scrolling P_ ((Lisp_Object, int, int, int, int));
static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *));
static int trailing_whitespace_p P_ ((int));
static int message_log_check_duplicate P_ ((int, int, int, int));
int invisible_p P_ ((Lisp_Object, Lisp_Object));
int invisible_ellipsis_p P_ ((Lisp_Object, Lisp_Object));
static void push_it P_ ((struct it *));
static void pop_it P_ ((struct it *));
static void sync_frame_with_window_matrix_rows P_ ((struct window *));
static void redisplay_internal P_ ((int));
static int echo_area_display P_ ((int));
static void redisplay_windows P_ ((Lisp_Object));
static void redisplay_window P_ ((Lisp_Object, int));
static void update_menu_bar P_ ((struct frame *, 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 int display_mode_lines P_ ((struct window *));
static int display_mode_line P_ ((struct window *, enum face_id, Lisp_Object));
static int display_mode_element P_ ((struct it *, int, int, int, Lisp_Object));
static char *decode_mode_spec P_ ((struct window *, int, int, int, int *));
static void display_menu_bar P_ ((struct window *));
static int display_count_lines P_ ((int, int, int, int, int *));
static int display_string P_ ((unsigned char *, Lisp_Object, Lisp_Object,
int, int, struct it *, int, int, int, int));
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 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 back_to_previous_visible_line_start P_ ((struct it *));
static void reseat_at_previous_visible_line_start P_ ((struct it *));
static void reseat_at_next_visible_line_start P_ ((struct it *, int));
static int next_element_from_display_vector P_ ((struct it *));
static int next_element_from_string P_ ((struct it *));
static int next_element_from_c_string P_ ((struct it *));
static int next_element_from_buffer P_ ((struct it *));
static int next_element_from_composition P_ ((struct it *));
static int next_element_from_image P_ ((struct it *));
static int next_element_from_stretch P_ ((struct it *));
static void load_overlay_strings P_ ((struct it *, int));
static int init_from_display_pos P_ ((struct it *, struct window *,
struct display_pos *));
static void reseat_to_string P_ ((struct it *, unsigned char *,
Lisp_Object, int, int, int, int));
static enum move_it_result move_it_in_display_line_to P_ ((struct it *,
int, int, int));
void move_it_vertically_backward P_ ((struct it *, int));
static void init_to_row_start P_ ((struct it *, struct window *,
struct glyph_row *));
static int init_to_row_end P_ ((struct it *, struct window *,
struct glyph_row *));
static void back_to_previous_line_start P_ ((struct it *));
static int forward_to_next_line_start P_ ((struct it *, int *));
static struct text_pos string_pos_nchars_ahead P_ ((struct text_pos,
Lisp_Object, int));
static struct text_pos string_pos P_ ((int, Lisp_Object));
static struct text_pos c_string_pos P_ ((int, unsigned char *, int));
static int number_of_chars P_ ((unsigned char *, int));
static void compute_stop_pos P_ ((struct it *));
static void compute_string_pos P_ ((struct text_pos *, struct text_pos,
Lisp_Object));
static int face_before_or_after_it_pos P_ ((struct it *, int));
static int next_overlay_change P_ ((int));
static int handle_single_display_prop P_ ((struct it *, Lisp_Object,
Lisp_Object, struct text_pos *,
int));
static int underlying_face_id P_ ((struct it *));
static int in_ellipses_for_invisible_text_p P_ ((struct display_pos *,
struct window *));
#define face_before_it_pos(IT) face_before_or_after_it_pos ((IT), 1)
#define face_after_it_pos(IT) face_before_or_after_it_pos ((IT), 0)
#ifdef HAVE_WINDOW_SYSTEM
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 *));
#endif
INLINE int
window_text_bottom_y (w)
struct window *w;
{
struct frame *f = XFRAME (w->frame);
int height = XFASTINT (w->height) * CANON_Y_UNIT (f);
if (WINDOW_WANTS_MODELINE_P (w))
height -= CURRENT_MODE_LINE_HEIGHT (w);
return height;
}
INLINE int
window_box_width (w, area)
struct window *w;
int area;
{
struct frame *f = XFRAME (w->frame);
int width = XFASTINT (w->width);
if (!w->pseudo_window_p)
{
width -= FRAME_SCROLL_BAR_WIDTH (f) + FRAME_FLAGS_AREA_COLS (f);
if (area == TEXT_AREA)
{
if (INTEGERP (w->left_margin_width))
width -= XFASTINT (w->left_margin_width);
if (INTEGERP (w->right_margin_width))
width -= XFASTINT (w->right_margin_width);
}
else if (area == LEFT_MARGIN_AREA)
width = (INTEGERP (w->left_margin_width)
? XFASTINT (w->left_margin_width) : 0);
else if (area == RIGHT_MARGIN_AREA)
width = (INTEGERP (w->right_margin_width)
? XFASTINT (w->right_margin_width) : 0);
}
return width * CANON_X_UNIT (f);
}
INLINE int
window_box_height (w)
struct window *w;
{
struct frame *f = XFRAME (w->frame);
int height = XFASTINT (w->height) * CANON_Y_UNIT (f);
xassert (height >= 0);
if (WINDOW_WANTS_MODELINE_P (w))
{
struct glyph_row *ml_row
= (w->current_matrix && w->current_matrix->rows
? MATRIX_MODE_LINE_ROW (w->current_matrix)
: 0);
if (ml_row && ml_row->mode_line_p)
height -= ml_row->height;
else
height -= estimate_mode_line_height (f, MODE_LINE_FACE_ID);
}
if (WINDOW_WANTS_HEADER_LINE_P (w))
{
struct glyph_row *hl_row
= (w->current_matrix && w->current_matrix->rows
? MATRIX_HEADER_LINE_ROW (w->current_matrix)
: 0);
if (hl_row && hl_row->mode_line_p)
height -= hl_row->height;
else
height -= estimate_mode_line_height (f, HEADER_LINE_FACE_ID);
}
return height;
}
INLINE int
window_box_left (w, area)
struct window *w;
int area;
{
struct frame *f = XFRAME (w->frame);
int x = FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
if (!w->pseudo_window_p)
{
x += (WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f)
+ FRAME_LEFT_FLAGS_AREA_WIDTH (f));
if (area == TEXT_AREA)
x += window_box_width (w, LEFT_MARGIN_AREA);
else if (area == RIGHT_MARGIN_AREA)
x += (window_box_width (w, LEFT_MARGIN_AREA)
+ window_box_width (w, TEXT_AREA));
}
return x;
}
INLINE int
window_box_right (w, area)
struct window *w;
int area;
{
return window_box_left (w, area) + window_box_width (w, area);
}
INLINE void
window_box (w, area, box_x, box_y, box_width, box_height)
struct window *w;
int area;
int *box_x, *box_y, *box_width, *box_height;
{
struct frame *f = XFRAME (w->frame);
*box_width = window_box_width (w, area);
*box_height = window_box_height (w);
*box_x = window_box_left (w, area);
*box_y = (FRAME_INTERNAL_BORDER_WIDTH_SAFE (f)
+ XFASTINT (w->top) * CANON_Y_UNIT (f));
if (WINDOW_WANTS_HEADER_LINE_P (w))
*box_y += CURRENT_HEADER_LINE_HEIGHT (w);
}
INLINE void
window_box_edges (w, area, top_left_x, top_left_y,
bottom_right_x, bottom_right_y)
struct window *w;
int area;
int *top_left_x, *top_left_y, *bottom_right_x, *bottom_right_y;
{
window_box (w, area, top_left_x, top_left_y, bottom_right_x,
bottom_right_y);
*bottom_right_x += *top_left_x;
*bottom_right_y += *top_left_y;
}
int
line_bottom_y (it)
struct it *it;
{
int line_height = it->max_ascent + it->max_descent;
int line_top_y = it->current_y;
if (line_height == 0)
{
if (last_height)
line_height = last_height;
else if (IT_CHARPOS (*it) < ZV)
{
move_it_by_lines (it, 1, 1);
line_height = (it->max_ascent || it->max_descent
? it->max_ascent + it->max_descent
: last_height);
}
else
{
struct glyph_row *row = it->glyph_row;
it->glyph_row = NULL;
it->what = IT_CHARACTER;
it->c = ' ';
it->len = 1;
PRODUCE_GLYPHS (it);
line_height = it->ascent + it->descent;
it->glyph_row = row;
}
}
return line_top_y + line_height;
}
int
pos_visible_p (w, charpos, fully, exact_mode_line_heights_p)
struct window *w;
int charpos, *fully, exact_mode_line_heights_p;
{
struct it it;
struct text_pos top;
int visible_p;
struct buffer *old_buffer = NULL;
if (XBUFFER (w->buffer) != current_buffer)
{
old_buffer = current_buffer;
set_buffer_internal_1 (XBUFFER (w->buffer));
}
*fully = visible_p = 0;
SET_TEXT_POS_FROM_MARKER (top, w->start);
if (exact_mode_line_heights_p)
{
if (WINDOW_WANTS_MODELINE_P (w))
current_mode_line_height
= display_mode_line (w, MODE_LINE_FACE_ID,
current_buffer->mode_line_format);
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);
if (IT_CHARPOS (it) >= charpos)
{
int top_y = it.current_y;
int bottom_y = line_bottom_y (&it);
int window_top_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
if (top_y < window_top_y)
visible_p = bottom_y > window_top_y;
else if (top_y < it.last_visible_y)
{
visible_p = 1;
*fully = bottom_y <= it.last_visible_y;
}
}
else if (it.current_y + it.max_ascent + it.max_descent > it.last_visible_y)
{
move_it_by_lines (&it, 1, 0);
if (charpos < IT_CHARPOS (it))
{
visible_p = 1;
*fully = 0;
}
}
if (old_buffer)
set_buffer_internal_1 (old_buffer);
current_header_line_height = current_mode_line_height = -1;
return visible_p;
}
static INLINE int
string_char_and_length (str, maxlen, len)
unsigned char *str;
int maxlen, *len;
{
int c;
c = STRING_CHAR_AND_LENGTH (str, maxlen, *len);
if (!CHAR_VALID_P (c, 1))
c = '?';
return c;
}
static struct text_pos
string_pos_nchars_ahead (pos, string, nchars)
struct text_pos pos;
Lisp_Object string;
int nchars;
{
xassert (STRINGP (string) && nchars >= 0);
if (STRING_MULTIBYTE (string))
{
int rest = STRING_BYTES (XSTRING (string)) - BYTEPOS (pos);
unsigned char *p = XSTRING (string)->data + BYTEPOS (pos);
int len;
while (nchars--)
{
string_char_and_length (p, rest, &len);
p += len, rest -= len;
xassert (rest >= 0);
CHARPOS (pos) += 1;
BYTEPOS (pos) += len;
}
}
else
SET_TEXT_POS (pos, CHARPOS (pos) + nchars, BYTEPOS (pos) + nchars);
return pos;
}
static INLINE struct text_pos
string_pos (charpos, string)
int charpos;
Lisp_Object string;
{
struct text_pos pos;
xassert (STRINGP (string));
xassert (charpos >= 0);
SET_TEXT_POS (pos, charpos, string_char_to_byte (string, charpos));
return pos;
}
static struct text_pos
c_string_pos (charpos, s, multibyte_p)
int charpos;
unsigned char *s;
int multibyte_p;
{
struct text_pos pos;
xassert (s != NULL);
xassert (charpos >= 0);
if (multibyte_p)
{
int rest = strlen (s), len;
SET_TEXT_POS (pos, 0, 0);
while (charpos--)
{
string_char_and_length (s, rest, &len);
s += len, rest -= len;
xassert (rest >= 0);
CHARPOS (pos) += 1;
BYTEPOS (pos) += len;
}
}
else
SET_TEXT_POS (pos, charpos, charpos);
return pos;
}
static int
number_of_chars (s, multibyte_p)
unsigned char *s;
int multibyte_p;
{
int nchars;
if (multibyte_p)
{
int rest = strlen (s), len;
unsigned char *p = (unsigned char *) s;
for (nchars = 0; rest > 0; ++nchars)
{
string_char_and_length (p, rest, &len);
rest -= len, p += len;
}
}
else
nchars = strlen (s);
return nchars;
}
static void
compute_string_pos (newpos, pos, string)
struct text_pos *newpos, pos;
Lisp_Object string;
{
xassert (STRINGP (string));
xassert (CHARPOS (*newpos) >= CHARPOS (pos));
if (STRING_MULTIBYTE (string))
*newpos = string_pos_nchars_ahead (pos, string,
CHARPOS (*newpos) - CHARPOS (pos));
else
BYTEPOS (*newpos) = CHARPOS (*newpos);
}
static Lisp_Object
safe_eval_handler (arg)
Lisp_Object arg;
{
add_to_log ("Error during redisplay: %s", arg, Qnil);
return Qnil;
}
Lisp_Object
safe_eval (sexpr)
Lisp_Object sexpr;
{
Lisp_Object val;
if (inhibit_eval_during_redisplay)
val = Qnil;
else
{
int count = BINDING_STACK_SIZE ();
struct gcpro gcpro1;
GCPRO1 (sexpr);
specbind (Qinhibit_redisplay, Qt);
val = internal_condition_case_1 (Feval, sexpr, Qerror,
safe_eval_handler);
UNGCPRO;
val = unbind_to (count, val);
}
return val;
}
Lisp_Object
safe_call (nargs, args)
int nargs;
Lisp_Object *args;
{
Lisp_Object val;
if (inhibit_eval_during_redisplay)
val = Qnil;
else
{
int count = BINDING_STACK_SIZE ();
struct gcpro gcpro1;
GCPRO1 (args[0]);
gcpro1.nvars = nargs;
specbind (Qinhibit_redisplay, Qt);
val = internal_condition_case_2 (Ffuncall, nargs, args, Qerror,
safe_eval_handler);
UNGCPRO;
val = unbind_to (count, val);
}
return val;
}
Lisp_Object
safe_call1 (fn, arg)
Lisp_Object fn, arg;
{
Lisp_Object args[2];
args[0] = fn;
args[1] = arg;
return safe_call (2, args);
}
#if 0
static void
check_it (it)
struct it *it;
{
if (it->method == next_element_from_string)
{
xassert (STRINGP (it->string));
xassert (IT_STRING_CHARPOS (*it) >= 0);
}
else if (it->method == next_element_from_buffer)
{
xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it)));
}
if (it->dpvec)
xassert (it->current.dpvec_index >= 0);
else
xassert (it->current.dpvec_index < 0);
}
#define CHECK_IT(IT) check_it ((IT))
#else
#define CHECK_IT(IT) (void) 0
#endif
#if GLYPH_DEBUG
static void
check_window_end (w)
struct window *w;
{
if (!MINI_WINDOW_P (w)
&& !NILP (w->window_end_valid))
{
struct glyph_row *row;
xassert ((row = MATRIX_ROW (w->current_matrix,
XFASTINT (w->window_end_vpos)),
!row->enabled_p
|| MATRIX_ROW_DISPLAYS_TEXT_P (row)
|| MATRIX_ROW_VPOS (row, w->current_matrix) == 0));
}
}
#define CHECK_WINDOW_END(W) check_window_end ((W))
#else
#define CHECK_WINDOW_END(W) (void) 0
#endif
void
init_iterator (it, w, charpos, bytepos, row, base_face_id)
struct it *it;
struct window *w;
int charpos, bytepos;
struct glyph_row *row;
enum face_id base_face_id;
{
int highlight_region_p;
xassert (w != NULL && it != NULL);
xassert (charpos < 0 || (charpos > 0 && charpos <= ZV));
if (face_change_count)
{
face_change_count = 0;
free_all_realized_faces (Qnil);
}
if (row == NULL)
{
if (base_face_id == MODE_LINE_FACE_ID)
row = MATRIX_MODE_LINE_ROW (w->desired_matrix);
else if (base_face_id == HEADER_LINE_FACE_ID)
row = MATRIX_HEADER_LINE_ROW (w->desired_matrix);
}
bzero (it, sizeof *it);
it->current.overlay_string_index = -1;
it->current.dpvec_index = -1;
it->base_face_id = base_face_id;
XSETWINDOW (it->window, w);
it->w = w;
it->f = XFRAME (w->frame);
if (base_face_id == DEFAULT_FACE_ID
&& FRAME_WINDOW_P (it->f))
{
if (NATNUMP (current_buffer->extra_line_spacing))
it->extra_line_spacing = XFASTINT (current_buffer->extra_line_spacing);
else if (it->f->extra_line_spacing > 0)
it->extra_line_spacing = it->f->extra_line_spacing;
}
if (
#ifndef WINDOWSNT
noninteractive &&
#endif
FRAME_FACE_CACHE (it->f) == NULL)
init_frame_faces (it->f);
if (FRAME_FACE_CACHE (it->f)->used == 0)
recompute_basic_faces (it->f);
it->space_width = Qnil;
it->font_height = Qnil;
it->ctl_arrow_p = !NILP (current_buffer->ctl_arrow);
it->selective = (INTEGERP (current_buffer->selective_display)
? XFASTINT (current_buffer->selective_display)
: (!NILP (current_buffer->selective_display)
? -1 : 0));
it->selective_display_ellipsis_p
= !NILP (current_buffer->selective_display_ellipses);
it->dp = window_display_table (w);
it->multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
highlight_region_p
= (!NILP (Vtransient_mark_mode)
&& !NILP (current_buffer->mark_active)
&& XMARKER (current_buffer->mark)->buffer != 0);
if (highlight_region_p
&& (
highlight_nonselected_windows
|| w == XWINDOW (selected_window)
|| (MINI_WINDOW_P (XWINDOW (selected_window))
&& WINDOWP (Vminibuf_scroll_window)
&& w == XWINDOW (Vminibuf_scroll_window))))
{
int charpos = marker_position (current_buffer->mark);
it->region_beg_charpos = min (PT, charpos);
it->region_end_charpos = max (PT, charpos);
}
else
it->region_beg_charpos = it->region_end_charpos = -1;
if (MARKERP (w->redisplay_end_trigger)
&& XMARKER (w->redisplay_end_trigger)->buffer != 0)
it->redisplay_end_trigger_charpos
= marker_position (w->redisplay_end_trigger);
else if (INTEGERP (w->redisplay_end_trigger))
it->redisplay_end_trigger_charpos = XINT (w->redisplay_end_trigger);
it->tab_width = XINT (current_buffer->tab_width);
if (it->tab_width <= 0 || it->tab_width > 1000)
it->tab_width = 8;
it->truncate_lines_p
= (base_face_id != DEFAULT_FACE_ID
|| XINT (it->w->hscroll)
|| (truncate_partial_width_windows
&& !WINDOW_FULL_WIDTH_P (it->w))
|| !NILP (current_buffer->truncate_lines));
if (!FRAME_WINDOW_P (it->f))
{
if (it->truncate_lines_p)
{
xassert (it->glyph_row == NULL);
produce_special_glyphs (it, IT_TRUNCATION);
it->truncation_pixel_width = it->pixel_width;
}
else
{
xassert (it->glyph_row == NULL);
produce_special_glyphs (it, IT_CONTINUATION);
it->continuation_pixel_width = it->pixel_width;
}
it->pixel_width = it->ascent = it->descent = 0;
it->phys_ascent = it->phys_descent = 0;
}
it->glyph_row = row;
it->area = TEXT_AREA;
if (base_face_id != DEFAULT_FACE_ID)
{
it->first_visible_x = 0;
it->last_visible_x = XFASTINT (w->width) * CANON_X_UNIT (it->f);
}
else
{
it->first_visible_x
= XFASTINT (it->w->hscroll) * CANON_X_UNIT (it->f);
it->last_visible_x = (it->first_visible_x
+ window_box_width (w, TEXT_AREA));
if (!FRAME_WINDOW_P (it->f))
{
if (it->truncate_lines_p)
it->last_visible_x -= it->truncation_pixel_width;
else
it->last_visible_x -= it->continuation_pixel_width;
}
it->header_line_p = WINDOW_WANTS_HEADER_LINE_P (w);
it->current_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w) + w->vscroll;
}
if (!FRAME_WINDOW_P (it->f)
&& !WINDOW_RIGHTMOST_P (it->w))
it->last_visible_x -= 1;
it->last_visible_y = window_text_bottom_y (w);
if (base_face_id != DEFAULT_FACE_ID)
{
struct face *face;
it->face_id = base_face_id;
face = FACE_FROM_ID (it->f, base_face_id);
if (face->box != FACE_NO_BOX)
it->start_of_box_run_p = 1;
}
if (charpos > 0)
{
it->end_charpos = ZV;
it->face_id = -1;
IT_CHARPOS (*it) = charpos;
if (bytepos <= 0)
IT_BYTEPOS (*it) = CHAR_TO_BYTE (charpos);
else
IT_BYTEPOS (*it) = bytepos;
reseat (it, it->current.pos, 1);
}
CHECK_IT (it);
}
void
start_display (it, w, pos)
struct it *it;
struct window *w;
struct text_pos pos;
{
struct glyph_row *row;
int first_vpos = WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0;
row = w->desired_matrix->rows + first_vpos;
init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID);
if (!it->truncate_lines_p)
{
int start_at_line_beg_p;
int first_y = it->current_y;
start_at_line_beg_p = (CHARPOS (pos) == BEGV
|| FETCH_BYTE (BYTEPOS (pos) - 1) == '\n');
if (!start_at_line_beg_p)
{
reseat_at_previous_visible_line_start (it);
move_it_to (it, CHARPOS (pos), -1, -1, -1, MOVE_TO_POS);
if (it->current_x > 0)
{
if (it->current.dpvec_index >= 0
|| it->current.overlay_string_index >= 0)
{
set_iterator_to_next (it, 1);
move_it_in_display_line_to (it, -1, -1, 0);
}
it->continuation_lines_width += it->current_x;
}
it->max_ascent = it->max_descent = 0;
it->max_phys_ascent = it->max_phys_descent = 0;
it->current_y = first_y;
it->vpos = 0;
it->current_x = it->hpos = 0;
}
}
#if 0
xassert (it->continuation_lines_width
|| IT_CHARPOS (it) == BEGV
|| FETCH_BYTE (IT_BYTEPOS (it) - 1) == '\n');
#endif
}
static int
in_ellipses_for_invisible_text_p (pos, w)
struct display_pos *pos;
struct window *w;
{
Lisp_Object prop, window;
int ellipses_p = 0;
int charpos = CHARPOS (pos->pos);
if (pos->dpvec_index >= 0
&& pos->overlay_string_index < 0
&& CHARPOS (pos->string_pos) < 0
&& charpos > BEGV
&& (XSETWINDOW (window, w),
prop = Fget_char_property (make_number (charpos),
Qinvisible, window),
!TEXT_PROP_MEANS_INVISIBLE (prop)))
{
prop = Fget_char_property (make_number (charpos - 1), Qinvisible,
window);
if (TEXT_PROP_MEANS_INVISIBLE (prop)
&& TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (prop))
ellipses_p = 1;
}
return ellipses_p;
}
static int
init_from_display_pos (it, w, pos)
struct it *it;
struct window *w;
struct display_pos *pos;
{
int charpos = CHARPOS (pos->pos), bytepos = BYTEPOS (pos->pos);
int i, overlay_strings_with_newlines = 0;
if (in_ellipses_for_invisible_text_p (pos, w))
{
--charpos;
bytepos = 0;
}
init_iterator (it, w, charpos, bytepos, NULL, DEFAULT_FACE_ID);
for (i = 0; i < it->n_overlay_strings; ++i)
{
char *s = XSTRING (it->overlay_strings[i])->data;
char *e = s + STRING_BYTES (XSTRING (it->overlay_strings[i]));
while (s < e && *s != '\n')
++s;
if (s < e)
{
overlay_strings_with_newlines = 1;
break;
}
}
if (pos->overlay_string_index >= 0)
{
int relative_index;
if (it->method == next_element_from_image)
pop_it (it);
if (pos->overlay_string_index >= OVERLAY_STRING_CHUNK_SIZE)
{
int n = pos->overlay_string_index / OVERLAY_STRING_CHUNK_SIZE;
it->current.overlay_string_index = 0;
while (n--)
{
load_overlay_strings (it, 0);
it->current.overlay_string_index += OVERLAY_STRING_CHUNK_SIZE;
}
}
it->current.overlay_string_index = pos->overlay_string_index;
relative_index = (it->current.overlay_string_index
% OVERLAY_STRING_CHUNK_SIZE);
it->string = it->overlay_strings[relative_index];
xassert (STRINGP (it->string));
it->current.string_pos = pos->string_pos;
it->method = next_element_from_string;
}
#if 0
else if (it->current.overlay_string_index >= 0)
{
while (it->sp)
pop_it (it);
it->current.overlay_string_index = -1;
it->method = next_element_from_buffer;
if (CHARPOS (pos->pos) == ZV)
it->overlay_strings_at_end_processed_p = 1;
}
#endif
if (CHARPOS (pos->string_pos) >= 0)
{
it->current.string_pos = pos->string_pos;
xassert (STRINGP (it->string));
}
if (pos->dpvec_index >= 0)
{
if (it->dpvec == NULL)
get_next_display_element (it);
xassert (it->dpvec && it->current.dpvec_index == 0);
it->current.dpvec_index = pos->dpvec_index;
}
CHECK_IT (it);
return !overlay_strings_with_newlines;
}
static void
init_to_row_start (it, w, row)
struct it *it;
struct window *w;
struct glyph_row *row;
{
init_from_display_pos (it, w, &row->start);
it->continuation_lines_width = row->continuation_lines_width;
CHECK_IT (it);
}
static int
init_to_row_end (it, w, row)
struct it *it;
struct window *w;
struct glyph_row *row;
{
int success = 0;
if (init_from_display_pos (it, w, &row->end))
{
if (row->continued_p)
it->continuation_lines_width
= row->continuation_lines_width + row->pixel_width;
CHECK_IT (it);
success = 1;
}
return success;
}
static void
handle_stop (it)
struct it *it;
{
enum prop_handled handled;
int handle_overlay_change_p = 1;
struct props *p;
it->dpvec = NULL;
it->current.dpvec_index = -1;
do
{
handled = HANDLED_NORMALLY;
for (p = it_props; p->handler; ++p)
{
handled = p->handler (it);
if (handled == HANDLED_RECOMPUTE_PROPS)
break;
else if (handled == HANDLED_RETURN)
return;
else if (handled == HANDLED_OVERLAY_STRING_CONSUMED)
handle_overlay_change_p = 0;
}
if (handled != HANDLED_RECOMPUTE_PROPS)
{
if (it->method == next_element_from_display_vector)
handle_overlay_change_p = 0;
if (handle_overlay_change_p)
handled = handle_overlay_change (it);
if (handled == HANDLED_NORMALLY)
compute_stop_pos (it);
}
}
while (handled == HANDLED_RECOMPUTE_PROPS);
}
static void
compute_stop_pos (it)
struct it *it;
{
register INTERVAL iv, next_iv;
Lisp_Object object, limit, position;
it->stop_charpos = it->end_charpos;
if (STRINGP (it->string))
{
object = it->string;
limit = Qnil;
position = make_number (IT_STRING_CHARPOS (*it));
}
else
{
int charpos;
charpos = next_overlay_change (IT_CHARPOS (*it));
if (charpos < it->stop_charpos)
it->stop_charpos = charpos;
if (it->region_beg_charpos > 0)
{
if (IT_CHARPOS (*it) < it->region_beg_charpos)
it->stop_charpos = min (it->stop_charpos, it->region_beg_charpos);
else if (IT_CHARPOS (*it) < it->region_end_charpos)
it->stop_charpos = min (it->stop_charpos, it->region_end_charpos);
}
XSETBUFFER (object, current_buffer);
limit = make_number (IT_CHARPOS (*it) + TEXT_PROP_DISTANCE_LIMIT);
position = make_number (IT_CHARPOS (*it));
}
iv = validate_interval_range (object, &position, &position, 0);
if (!NULL_INTERVAL_P (iv))
{
Lisp_Object values_here[LAST_PROP_IDX];
struct props *p;
for (p = it_props; p->handler; ++p)
values_here[p->idx] = textget (iv->plist, *p->name);
for (next_iv = next_interval (iv);
(!NULL_INTERVAL_P (next_iv)
&& (NILP (limit)
|| XFASTINT (limit) > next_iv->position));
next_iv = next_interval (next_iv))
{
for (p = it_props; p->handler; ++p)
{
Lisp_Object new_value;
new_value = textget (next_iv->plist, *p->name);
if (!EQ (values_here[p->idx], new_value))
break;
}
if (p->handler)
break;
}
if (!NULL_INTERVAL_P (next_iv))
{
if (INTEGERP (limit)
&& next_iv->position >= XFASTINT (limit))
it->stop_charpos = min (XFASTINT (limit), it->stop_charpos);
else
it->stop_charpos = min (it->stop_charpos, next_iv->position);
}
}
xassert (STRINGP (it->string)
|| (it->stop_charpos >= BEGV
&& it->stop_charpos >= IT_CHARPOS (*it)));
}
static int
next_overlay_change (pos)
int pos;
{
int noverlays;
int endpos;
Lisp_Object *overlays;
int len;
int i;
len = 10;
overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
if (noverlays > len)
{
len = noverlays;
overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
}
for (i = 0; i < noverlays; ++i)
{
Lisp_Object oend;
int oendpos;
oend = OVERLAY_END (overlays[i]);
oendpos = OVERLAY_POSITION (oend);
endpos = min (endpos, oendpos);
}
return endpos;
}
static enum prop_handled
handle_fontified_prop (it)
struct it *it;
{
Lisp_Object prop, pos;
enum prop_handled handled = HANDLED_NORMALLY;
if (!STRINGP (it->string)
&& it->s == NULL
&& !NILP (Vfontification_functions)
&& !NILP (Vrun_hooks)
&& (pos = make_number (IT_CHARPOS (*it)),
prop = Fget_char_property (pos, Qfontified, Qnil),
NILP (prop)))
{
int count = BINDING_STACK_SIZE ();
Lisp_Object val;
val = Vfontification_functions;
specbind (Qfontification_functions, Qnil);
specbind (Qafter_change_functions, Qnil);
if (!CONSP (val) || EQ (XCAR (val), Qlambda))
safe_call1 (val, pos);
else
{
Lisp_Object globals, fn;
struct gcpro gcpro1, gcpro2;
globals = Qnil;
GCPRO2 (val, globals);
for (; CONSP (val); val = XCDR (val))
{
fn = XCAR (val);
if (EQ (fn, Qt))
{
for (globals = Fdefault_value (Qfontification_functions);
CONSP (globals);
globals = XCDR (globals))
{
fn = XCAR (globals);
if (!EQ (fn, Qt))
safe_call1 (fn, pos);
}
}
else
safe_call1 (fn, pos);
}
UNGCPRO;
}
unbind_to (count, Qnil);
if (!NILP (Fget_char_property (pos, Qfontified, Qnil)))
handled = HANDLED_RECOMPUTE_PROPS;
}
return handled;
}
static enum prop_handled
handle_face_prop (it)
struct it *it;
{
int new_face_id, next_stop;
if (!STRINGP (it->string))
{
new_face_id
= face_at_buffer_position (it->w,
IT_CHARPOS (*it),
it->region_beg_charpos,
it->region_end_charpos,
&next_stop,
(IT_CHARPOS (*it)
+ TEXT_PROP_DISTANCE_LIMIT),
0);
if (new_face_id != it->face_id)
{
struct face *new_face = FACE_FROM_ID (it->f, new_face_id);
it->start_of_box_run_p
= (new_face->box != FACE_NO_BOX
&& (it->face_id >= 0
|| IT_CHARPOS (*it) == BEG
|| new_face_id != face_before_it_pos (it)));
it->face_box_p = new_face->box != FACE_NO_BOX;
}
}
else
{
int base_face_id, bufpos;
if (it->current.overlay_string_index >= 0)
bufpos = IT_CHARPOS (*it);
else
bufpos = 0;
base_face_id = underlying_face_id (it);
new_face_id = face_at_string_position (it->w,
it->string,
IT_STRING_CHARPOS (*it),
bufpos,
it->region_beg_charpos,
it->region_end_charpos,
&next_stop,
base_face_id, 0);
#if 0
if (it->glyph_row == MATRIX_MODE_LINE_ROW (it->w->desired_matrix)
&& new_face_id == DEFAULT_FACE_ID)
new_face_id = MODE_LINE_FACE_ID;
#endif
if (new_face_id != it->face_id)
{
struct face *new_face = FACE_FROM_ID (it->f, new_face_id);
struct face *old_face = FACE_FROM_ID (it->f, it->face_id);
it->start_of_box_run_p
= new_face->box && (old_face == NULL || !old_face->box);
it->face_box_p = new_face->box != FACE_NO_BOX;
}
}
it->face_id = new_face_id;
return HANDLED_NORMALLY;
}
static int
underlying_face_id (it)
struct it *it;
{
int face_id = it->base_face_id, i;
xassert (STRINGP (it->string));
for (i = it->sp - 1; i >= 0; --i)
if (NILP (it->stack[i].string))
face_id = it->stack[i].face_id;
return face_id;
}
static int
face_before_or_after_it_pos (it, before_p)
struct it *it;
int before_p;
{
int face_id, limit;
int next_check_charpos;
struct text_pos pos;
xassert (it->s == NULL);
if (STRINGP (it->string))
{
int bufpos, base_face_id;
if (IT_STRING_CHARPOS (*it) >= XSTRING (it->string)->size
|| (IT_STRING_CHARPOS (*it) == 0 && before_p))
return it->face_id;
if (before_p)
pos = string_pos (IT_STRING_CHARPOS (*it) - 1, it->string);
else
pos = (it->what == IT_COMPOSITION
? string_pos (IT_STRING_CHARPOS (*it) + it->cmp_len, it->string)
: string_pos (IT_STRING_CHARPOS (*it) + 1, it->string));
if (it->current.overlay_string_index >= 0)
bufpos = IT_CHARPOS (*it);
else
bufpos = 0;
base_face_id = underlying_face_id (it);
face_id = face_at_string_position (it->w,
it->string,
CHARPOS (pos),
bufpos,
it->region_beg_charpos,
it->region_end_charpos,
&next_check_charpos,
base_face_id, 0);
if (STRING_MULTIBYTE (it->string))
{
unsigned char *p = XSTRING (it->string)->data + BYTEPOS (pos);
int rest = STRING_BYTES (XSTRING (it->string)) - BYTEPOS (pos);
int c, len;
struct face *face = FACE_FROM_ID (it->f, face_id);
c = string_char_and_length (p, rest, &len);
face_id = FACE_FOR_CHAR (it->f, face, c);
}
}
else
{
if ((IT_CHARPOS (*it) >= ZV && !before_p)
|| (IT_CHARPOS (*it) <= BEGV && before_p))
return it->face_id;
limit = IT_CHARPOS (*it) + TEXT_PROP_DISTANCE_LIMIT;
pos = it->current.pos;
if (before_p)
DEC_TEXT_POS (pos, it->multibyte_p);
else
{
if (it->what == IT_COMPOSITION)
pos.charpos += it->cmp_len, pos.bytepos += it->len;
else
INC_TEXT_POS (pos, it->multibyte_p);
}
face_id = face_at_buffer_position (it->w,
CHARPOS (pos),
it->region_beg_charpos,
it->region_end_charpos,
&next_check_charpos,
limit, 0);
if (it->multibyte_p)
{
int c = FETCH_MULTIBYTE_CHAR (CHARPOS (pos));
struct face *face = FACE_FROM_ID (it->f, face_id);
face_id = FACE_FOR_CHAR (it->f, face, c);
}
}
return face_id;
}
static enum prop_handled
handle_invisible_prop (it)
struct it *it;
{
enum prop_handled handled = HANDLED_NORMALLY;
if (STRINGP (it->string))
{
extern Lisp_Object Qinvisible;
Lisp_Object prop, end_charpos, limit, charpos;
charpos = make_number (IT_STRING_CHARPOS (*it));
prop = Fget_text_property (charpos, Qinvisible, it->string);
if (!NILP (prop)
&& IT_STRING_CHARPOS (*it) < it->end_charpos)
{
handled = HANDLED_RECOMPUTE_PROPS;
XSETINT (limit, XSTRING (it->string)->size);
end_charpos = Fnext_single_property_change (charpos, Qinvisible,
it->string, limit);
if (INTEGERP (end_charpos)
&& XFASTINT (end_charpos) < XFASTINT (limit))
{
struct text_pos old;
old = it->current.string_pos;
IT_STRING_CHARPOS (*it) = XFASTINT (end_charpos);
compute_string_pos (&it->current.string_pos, old, it->string);
}
else
{
if (it->current.overlay_string_index >= 0)
{
next_overlay_string (it);
handled = HANDLED_OVERLAY_STRING_CONSUMED;
}
else
{
struct Lisp_String *s = XSTRING (it->string);
IT_STRING_CHARPOS (*it) = s->size;
IT_STRING_BYTEPOS (*it) = STRING_BYTES (s);
}
}
}
}
else
{
int visible_p, newpos, next_stop, start_charpos;
Lisp_Object pos, prop, overlay;
start_charpos = IT_CHARPOS (*it);
pos = make_number (IT_CHARPOS (*it));
prop = get_char_property_and_overlay (pos, Qinvisible, it->window,
&overlay);
if (TEXT_PROP_MEANS_INVISIBLE (prop)
&& IT_CHARPOS (*it) < it->end_charpos)
{
int display_ellipsis_p
= TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (prop);
handled = HANDLED_RECOMPUTE_PROPS;
do
{
newpos = skip_invisible (IT_CHARPOS (*it),
&next_stop, ZV, it->window);
if (newpos == IT_CHARPOS (*it) || newpos >= ZV)
visible_p = 1;
else
{
pos = make_number (newpos);
prop = Fget_char_property (pos, Qinvisible, it->window);
visible_p = !TEXT_PROP_MEANS_INVISIBLE (prop);
}
if (!visible_p)
IT_CHARPOS (*it) = next_stop;
}
while (!visible_p);
IT_CHARPOS (*it) = newpos;
IT_BYTEPOS (*it) = CHAR_TO_BYTE (newpos);
if (NILP (overlay)
&& get_overlay_strings (it, start_charpos))
{
handled = HANDLED_RECOMPUTE_PROPS;
it->stack[it->sp - 1].display_ellipsis_p = display_ellipsis_p;
}
else if (display_ellipsis_p)
setup_for_ellipsis (it);
}
}
return handled;
}
static void
setup_for_ellipsis (it)
struct it *it;
{
if (it->dp
&& VECTORP (DISP_INVIS_VECTOR (it->dp)))
{
struct Lisp_Vector *v = XVECTOR (DISP_INVIS_VECTOR (it->dp));
it->dpvec = v->contents;
it->dpend = v->contents + v->size;
}
else
{
it->dpvec = default_invis_vector;
it->dpend = default_invis_vector + 3;
}
it->dpvec_char_len = 0;
it->current.dpvec_index = 0;
it->method = next_element_from_display_vector;
}
static enum prop_handled
handle_display_prop (it)
struct it *it;
{
Lisp_Object prop, object;
struct text_pos *position;
int display_replaced_p = 0;
if (STRINGP (it->string))
{
object = it->string;
position = &it->current.string_pos;
}
else
{
object = it->w->buffer;
position = &it->current.pos;
}
it->font_height = Qnil;
it->space_width = Qnil;
it->voffset = 0;
if (!it->string_from_display_prop_p)
it->area = TEXT_AREA;
prop = Fget_char_property (make_number (position->charpos),
Qdisplay, object);
if (NILP (prop))
return HANDLED_NORMALLY;
if (CONSP (prop)
&& !EQ (XCAR (prop), Qimage)
&& !EQ (XCAR (prop), Qspace)
&& !EQ (XCAR (prop), Qwhen)
&& !EQ (XCAR (prop), Qspace_width)
&& !EQ (XCAR (prop), Qheight)
&& !EQ (XCAR (prop), Qraise)
&& !(CONSP (XCAR (prop)) && EQ (XCAR (XCAR (prop)), Qmargin))
&& !NILP (XCAR (prop)))
{
for (; CONSP (prop); prop = XCDR (prop))
{
if (handle_single_display_prop (it, XCAR (prop), object,
position, display_replaced_p))
display_replaced_p = 1;
}
}
else if (VECTORP (prop))
{
int i;
for (i = 0; i < ASIZE (prop); ++i)
if (handle_single_display_prop (it, AREF (prop, i), object,
position, display_replaced_p))
display_replaced_p = 1;
}
else
{
if (handle_single_display_prop (it, prop, object, position, 0))
display_replaced_p = 1;
}
return display_replaced_p ? HANDLED_RETURN : HANDLED_NORMALLY;
}
static struct text_pos
display_prop_end (it, object, start_pos)
struct it *it;
Lisp_Object object;
struct text_pos start_pos;
{
Lisp_Object end;
struct text_pos end_pos;
end = Fnext_single_char_property_change (make_number (CHARPOS (start_pos)),
Qdisplay, object, Qnil);
CHARPOS (end_pos) = XFASTINT (end);
if (STRINGP (object))
compute_string_pos (&end_pos, start_pos, it->string);
else
BYTEPOS (end_pos) = CHAR_TO_BYTE (XFASTINT (end));
return end_pos;
}
static int
handle_single_display_prop (it, prop, object, position,
display_replaced_before_p)
struct it *it;
Lisp_Object prop;
Lisp_Object object;
struct text_pos *position;
int display_replaced_before_p;
{
Lisp_Object value;
int replaces_text_display_p = 0;
Lisp_Object form;
form = Qt;
if (CONSP (prop) && EQ (XCAR (prop), Qwhen))
{
prop = XCDR (prop);
if (!CONSP (prop))
return 0;
form = XCAR (prop);
prop = XCDR (prop);
}
if (!NILP (form) && !EQ (form, Qt))
{
int count = BINDING_STACK_SIZE ();
struct gcpro gcpro1;
specbind (Qobject, object);
specbind (Qposition, make_number (CHARPOS (*position)));
specbind (Qbuffer_position,
make_number (STRINGP (object)
? IT_CHARPOS (*it) : CHARPOS (*position)));
GCPRO1 (form);
form = safe_eval (form);
UNGCPRO;
unbind_to (count, Qnil);
}
if (NILP (form))
return 0;
if (CONSP (prop)
&& EQ (XCAR (prop), Qheight)
&& CONSP (XCDR (prop)))
{
if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
return 0;
it->font_height = XCAR (XCDR (prop));
if (!NILP (it->font_height))
{
struct face *face = FACE_FROM_ID (it->f, it->face_id);
int new_height = -1;
if (CONSP (it->font_height)
&& (EQ (XCAR (it->font_height), Qplus)
|| EQ (XCAR (it->font_height), Qminus))
&& CONSP (XCDR (it->font_height))
&& INTEGERP (XCAR (XCDR (it->font_height))))
{
int steps = XINT (XCAR (XCDR (it->font_height)));
if (EQ (XCAR (it->font_height), Qplus))
steps = - steps;
it->face_id = smaller_face (it->f, it->face_id, steps);
}
else if (FUNCTIONP (it->font_height))
{
Lisp_Object height;
height = safe_call1 (it->font_height,
face->lface[LFACE_HEIGHT_INDEX]);
if (NUMBERP (height))
new_height = XFLOATINT (height);
}
else if (NUMBERP (it->font_height))
{
struct face *face;
face = FACE_FROM_ID (it->f, DEFAULT_FACE_ID);
new_height = (XFLOATINT (it->font_height)
* XINT (face->lface[LFACE_HEIGHT_INDEX]));
}
else
{
Lisp_Object value;
int count = BINDING_STACK_SIZE ();
specbind (Qheight, face->lface[LFACE_HEIGHT_INDEX]);
value = safe_eval (it->font_height);
unbind_to (count, Qnil);
if (NUMBERP (value))
new_height = XFLOATINT (value);
}
if (new_height > 0)
it->face_id = face_with_height (it->f, it->face_id, new_height);
}
}
else if (CONSP (prop)
&& EQ (XCAR (prop), Qspace_width)
&& CONSP (XCDR (prop)))
{
if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
return 0;
value = XCAR (XCDR (prop));
if (NUMBERP (value) && XFLOATINT (value) > 0)
it->space_width = value;
}
else if (CONSP (prop)
&& EQ (XCAR (prop), Qraise)
&& CONSP (XCDR (prop)))
{
if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
return 0;
#ifdef HAVE_WINDOW_SYSTEM
value = XCAR (XCDR (prop));
if (NUMBERP (value))
{
struct face *face = FACE_FROM_ID (it->f, it->face_id);
it->voffset = - (XFLOATINT (value)
* (FONT_HEIGHT (face->font)));
}
#endif
}
else if (!it->string_from_display_prop_p)
{
Lisp_Object location, value;
struct text_pos start_pos;
int valid_p;
start_pos = *position;
*position = display_prop_end (it, object, start_pos);
value = Qnil;
it->stop_charpos = position->charpos;
location = Qunbound;
if (CONSP (prop) && CONSP (XCAR (prop)))
{
Lisp_Object tem;
value = XCDR (prop);
if (CONSP (value))
value = XCAR (value);
tem = XCAR (prop);
if (EQ (XCAR (tem), Qmargin)
&& (tem = XCDR (tem),
tem = CONSP (tem) ? XCAR (tem) : Qnil,
(NILP (tem)
|| EQ (tem, Qleft_margin)
|| EQ (tem, Qright_margin))))
location = tem;
}
if (EQ (location, Qunbound))
{
location = Qnil;
value = prop;
}
#ifdef HAVE_WINDOW_SYSTEM
if (FRAME_TERMCAP_P (it->f))
valid_p = STRINGP (value);
else
valid_p = (STRINGP (value)
|| (CONSP (value) && EQ (XCAR (value), Qspace))
|| valid_image_p (value));
#else
valid_p = STRINGP (value);
#endif
if ((EQ (location, Qleft_margin)
|| EQ (location, Qright_margin)
|| NILP (location))
&& valid_p
&& !display_replaced_before_p)
{
replaces_text_display_p = 1;
push_it (it);
if (NILP (location))
it->area = TEXT_AREA;
else if (EQ (location, Qleft_margin))
it->area = LEFT_MARGIN_AREA;
else
it->area = RIGHT_MARGIN_AREA;
if (STRINGP (value))
{
it->string = value;
it->multibyte_p = STRING_MULTIBYTE (it->string);
it->current.overlay_string_index = -1;
IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0;
it->end_charpos = it->string_nchars
= XSTRING (it->string)->size;
it->method = next_element_from_string;
it->stop_charpos = 0;
it->string_from_display_prop_p = 1;
*position = start_pos;
}
else if (CONSP (value) && EQ (XCAR (value), Qspace))
{
it->method = next_element_from_stretch;
it->object = value;
it->current.pos = it->position = start_pos;
}
#ifdef HAVE_WINDOW_SYSTEM
else
{
it->what = IT_IMAGE;
it->image_id = lookup_image (it->f, value);
it->position = start_pos;
it->object = NILP (object) ? it->w->buffer : object;
it->method = next_element_from_image;
*position = start_pos;
}
#endif
}
else
*position = start_pos;
}
return replaces_text_display_p;
}
static int
single_display_prop_intangible_p (prop)
Lisp_Object prop;
{
if (CONSP (prop) && EQ (XCAR (prop), Qwhen))
{
prop = XCDR (prop);
if (!CONSP (prop))
return 0;
prop = XCDR (prop);
}
if (!CONSP (prop))
return 0;
if (EQ (XCAR (prop), Qmargin))
{
prop = XCDR (prop);
if (!CONSP (prop))
return 0;
prop = XCDR (prop);
if (!CONSP (prop)
|| EQ (XCAR (prop), Qleft_margin)
|| EQ (XCAR (prop), Qright_margin))
return 0;
}
return CONSP (prop) && EQ (XCAR (prop), Qimage);
}
int
display_prop_intangible_p (prop)
Lisp_Object prop;
{
if (CONSP (prop)
&& CONSP (XCAR (prop))
&& !EQ (Qmargin, XCAR (XCAR (prop))))
{
while (CONSP (prop))
{
if (single_display_prop_intangible_p (XCAR (prop)))
return 1;
prop = XCDR (prop);
}
}
else if (VECTORP (prop))
{
int i;
for (i = 0; i < ASIZE (prop); ++i)
if (single_display_prop_intangible_p (AREF (prop, i)))
return 1;
}
else
return single_display_prop_intangible_p (prop);
return 0;
}
static int
single_display_prop_string_p (prop, string)
Lisp_Object prop, string;
{
extern Lisp_Object Qwhen, Qmargin;
if (EQ (string, prop))
return 1;
if (CONSP (prop) && EQ (XCAR (prop), Qwhen))
{
prop = XCDR (prop);
if (!CONSP (prop))
return 0;
prop = XCDR (prop);
}
if (CONSP (prop))
if (EQ (XCAR (prop), Qmargin))
{
prop = XCDR (prop);
if (!CONSP (prop))
return 0;
prop = XCDR (prop);
if (!CONSP (prop))
return 0;
}
return CONSP (prop) && EQ (XCAR (prop), string);
}
static int
display_prop_string_p (prop, string)
Lisp_Object prop, string;
{
extern Lisp_Object Qwhen, Qmargin;
if (CONSP (prop)
&& CONSP (XCAR (prop))
&& !EQ (Qmargin, XCAR (XCAR (prop))))
{
while (CONSP (prop))
{
if (single_display_prop_string_p (XCAR (prop), string))
return 1;
prop = XCDR (prop);
}
}
else if (VECTORP (prop))
{
int i;
for (i = 0; i < ASIZE (prop); ++i)
if (single_display_prop_string_p (AREF (prop, i), string))
return 1;
}
else
return single_display_prop_string_p (prop, string);
return 0;
}
int
string_buffer_position (w, string, around_charpos)
struct window *w;
Lisp_Object string;
int around_charpos;
{
Lisp_Object around = make_number (around_charpos);
Lisp_Object limit, prop, pos;
const int MAX_DISTANCE = 1000;
int found = 0;
pos = make_number (around_charpos);
limit = make_number (min (XINT (pos) + MAX_DISTANCE, ZV));
while (!found && !EQ (pos, limit))
{
prop = Fget_char_property (pos, Qdisplay, Qnil);
if (!NILP (prop) && display_prop_string_p (prop, string))
found = 1;
else
pos = Fnext_single_char_property_change (pos, Qdisplay, Qnil, limit);
}
if (!found)
{
pos = make_number (around_charpos);
limit = make_number (max (XINT (pos) - MAX_DISTANCE, BEGV));
while (!found && !EQ (pos, limit))
{
prop = Fget_char_property (pos, Qdisplay, Qnil);
if (!NILP (prop) && display_prop_string_p (prop, string))
found = 1;
else
pos = Fprevious_single_char_property_change (pos, Qdisplay, Qnil,
limit);
}
}
return found ? XINT (pos) : 0;
}
static enum prop_handled
handle_composition_prop (it)
struct it *it;
{
Lisp_Object prop, string;
int pos, pos_byte, end;
enum prop_handled handled = HANDLED_NORMALLY;
if (STRINGP (it->string))
{
pos = IT_STRING_CHARPOS (*it);
pos_byte = IT_STRING_BYTEPOS (*it);
string = it->string;
}
else
{
pos = IT_CHARPOS (*it);
pos_byte = IT_BYTEPOS (*it);
string = Qnil;
}
if (find_composition (pos, -1, &pos, &end, &prop, string)
&& COMPOSITION_VALID_P (pos, end, prop)
&& (STRINGP (it->string) || (PT <= pos || PT >= end)))
{
int id = get_composition_id (pos, pos_byte, end - pos, prop, string);
if (id >= 0)
{
it->method = next_element_from_composition;
it->cmp_id = id;
it->cmp_len = COMPOSITION_LENGTH (prop);
it->c = COMPOSITION_GLYPH (composition_table[id], 0);
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;
}
}
return handled;
}
struct overlay_entry
{
Lisp_Object overlay;
Lisp_Object string;
int priority;
int after_string_p;
};
static enum prop_handled
handle_overlay_change (it)
struct it *it;
{
if (!STRINGP (it->string) && get_overlay_strings (it, 0))
return HANDLED_RECOMPUTE_PROPS;
else
return HANDLED_NORMALLY;
}
static void
next_overlay_string (it)
struct it *it;
{
++it->current.overlay_string_index;
if (it->current.overlay_string_index == it->n_overlay_strings)
{
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;
it->current.overlay_string_index = -1;
SET_TEXT_POS (it->current.string_pos, -1, -1);
it->n_overlay_strings = 0;
it->method = next_element_from_buffer;
if (IT_CHARPOS (*it) >= it->end_charpos)
it->overlay_strings_at_end_processed_p = 1;
if (display_ellipsis_p)
setup_for_ellipsis (it);
}
else
{
int i = it->current.overlay_string_index % OVERLAY_STRING_CHUNK_SIZE;
if (it->current.overlay_string_index && i == 0)
load_overlay_strings (it, 0);
it->string = it->overlay_strings[i];
it->multibyte_p = STRING_MULTIBYTE (it->string);
SET_TEXT_POS (it->current.string_pos, 0, 0);
it->method = next_element_from_string;
it->stop_charpos = 0;
}
CHECK_IT (it);
}
static int
compare_overlay_entries (e1, e2)
void *e1, *e2;
{
struct overlay_entry *entry1 = (struct overlay_entry *) e1;
struct overlay_entry *entry2 = (struct overlay_entry *) e2;
int result;
if (entry1->after_string_p != entry2->after_string_p)
{
if (EQ (entry1->overlay, entry2->overlay))
result = entry1->after_string_p ? 1 : -1;
else
result = entry1->after_string_p ? -1 : 1;
}
else if (entry1->after_string_p)
result = entry2->priority - entry1->priority;
else
result = entry1->priority - entry2->priority;
return result;
}
static void
load_overlay_strings (it, charpos)
struct it *it;
int charpos;
{
extern Lisp_Object Qafter_string, Qbefore_string, Qwindow, Qpriority;
Lisp_Object ov, overlay, window, str, invisible;
int start, end;
int size = 20;
int n = 0, i, j, invis_p;
struct overlay_entry *entries
= (struct overlay_entry *) alloca (size * sizeof *entries);
if (charpos <= 0)
charpos = IT_CHARPOS (*it);
#define RECORD_OVERLAY_STRING(OVERLAY, STRING, AFTER_P) \
do \
{ \
Lisp_Object priority; \
\
if (n == size) \
{ \
int new_size = 2 * size; \
struct overlay_entry *old = entries; \
entries = \
(struct overlay_entry *) alloca (new_size \
* sizeof *entries); \
bcopy (old, entries, size * sizeof *entries); \
size = new_size; \
} \
\
entries[n].string = (STRING); \
entries[n].overlay = (OVERLAY); \
priority = Foverlay_get ((OVERLAY), Qpriority); \
entries[n].priority = INTEGERP (priority) ? XINT (priority) : 0; \
entries[n].after_string_p = (AFTER_P); \
++n; \
} \
while (0)
for (ov = current_buffer->overlays_before; CONSP (ov); ov = XCDR (ov))
{
overlay = XCAR (ov);
xassert (OVERLAYP (overlay));
start = OVERLAY_POSITION (OVERLAY_START (overlay));
end = OVERLAY_POSITION (OVERLAY_END (overlay));
if (end < charpos)
break;
if (end != charpos && start != charpos)
continue;
window = Foverlay_get (overlay, Qwindow);
if (WINDOWP (window) && XWINDOW (window) != it->w)
continue;
invisible = Foverlay_get (overlay, Qinvisible);
invis_p = TEXT_PROP_MEANS_INVISIBLE (invisible);
if ((start == charpos || (end == charpos && invis_p))
&& (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str))
&& XSTRING (str)->size)
RECORD_OVERLAY_STRING (overlay, str, 0);
if ((end == charpos || (start == charpos && invis_p))
&& (str = Foverlay_get (overlay, Qafter_string), STRINGP (str))
&& XSTRING (str)->size)
RECORD_OVERLAY_STRING (overlay, str, 1);
}
for (ov = current_buffer->overlays_after; CONSP (ov); ov = XCDR (ov))
{
overlay = XCAR (ov);
xassert (OVERLAYP (overlay));
start = OVERLAY_POSITION (OVERLAY_START (overlay));
end = OVERLAY_POSITION (OVERLAY_END (overlay));
if (start > charpos)
break;
if (end != charpos && start != charpos)
continue;
window = Foverlay_get (overlay, Qwindow);
if (WINDOWP (window) && XWINDOW (window) != it->w)
continue;
invisible = Foverlay_get (overlay, Qinvisible);
invis_p = TEXT_PROP_MEANS_INVISIBLE (invisible);
if ((start == charpos || (end == charpos && invis_p))
&& (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str))
&& XSTRING (str)->size)
RECORD_OVERLAY_STRING (overlay, str, 0);
if ((end == charpos || (start == charpos && invis_p))
&& (str = Foverlay_get (overlay, Qafter_string), STRINGP (str))
&& XSTRING (str)->size)
RECORD_OVERLAY_STRING (overlay, str, 1);
}
#undef RECORD_OVERLAY_STRING
if (n > 1)
qsort (entries, n, sizeof *entries, compare_overlay_entries);
it->n_overlay_strings = n;
i = 0;
j = it->current.overlay_string_index;
while (i < OVERLAY_STRING_CHUNK_SIZE && j < n)
it->overlay_strings[i++] = entries[j++].string;
CHECK_IT (it);
}
static int
get_overlay_strings (it, charpos)
struct it *it;
int charpos;
{
it->current.overlay_string_index = 0;
load_overlay_strings (it, charpos);
if (it->n_overlay_strings)
{
compute_stop_pos (it);
xassert (it->face_id >= 0);
xassert (it->sp == 0);
push_it (it);
IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0;
it->string = it->overlay_strings[0];
it->stop_charpos = 0;
it->end_charpos = XSTRING (it->string)->size;
it->multibyte_p = STRING_MULTIBYTE (it->string);
xassert (STRINGP (it->string));
it->method = next_element_from_string;
}
else
{
it->string = Qnil;
it->current.overlay_string_index = -1;
it->method = next_element_from_buffer;
}
CHECK_IT (it);
return STRINGP (it->string);
}
static void
push_it (it)
struct it *it;
{
struct iterator_stack_entry *p;
xassert (it->sp < 2);
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->end_charpos = it->end_charpos;
p->string_nchars = it->string_nchars;
p->area = it->area;
p->multibyte_p = it->multibyte_p;
p->space_width = it->space_width;
p->font_height = it->font_height;
p->voffset = it->voffset;
p->string_from_display_prop_p = it->string_from_display_prop_p;
p->display_ellipsis_p = 0;
++it->sp;
}
static void
pop_it (it)
struct it *it;
{
struct iterator_stack_entry *p;
xassert (it->sp > 0);
--it->sp;
p = it->stack + it->sp;
it->stop_charpos = p->stop_charpos;
it->face_id = p->face_id;
it->string = p->string;
it->current = p->pos;
it->end_charpos = p->end_charpos;
it->string_nchars = p->string_nchars;
it->area = p->area;
it->multibyte_p = p->multibyte_p;
it->space_width = p->space_width;
it->font_height = p->font_height;
it->voffset = p->voffset;
it->string_from_display_prop_p = p->string_from_display_prop_p;
}
static void
back_to_previous_line_start (it)
struct it *it;
{
IT_CHARPOS (*it) = find_next_newline_no_quit (IT_CHARPOS (*it) - 1, -1);
IT_BYTEPOS (*it) = CHAR_TO_BYTE (IT_CHARPOS (*it));
}
static int
forward_to_next_line_start (it, skipped_p)
struct it *it;
int *skipped_p;
{
int old_selective, newline_found_p, n;
const int MAX_NEWLINE_DISTANCE = 500;
if (it->what == IT_CHARACTER
&& it->c == '\n'
&& CHARPOS (it->position) == IT_CHARPOS (*it))
{
set_iterator_to_next (it, 0);
it->c = 0;
return 1;
}
old_selective = it->selective;
it->selective = 0;
for (n = newline_found_p = 0;
!newline_found_p && n < MAX_NEWLINE_DISTANCE;
n += STRINGP (it->string) ? 0 : 1)
{
if (!get_next_display_element (it))
break;
newline_found_p = it->what == IT_CHARACTER && it->c == '\n';
set_iterator_to_next (it, 0);
}
if (n == MAX_NEWLINE_DISTANCE)
{
int start = IT_CHARPOS (*it);
int limit = find_next_newline_no_quit (start, 1);
Lisp_Object pos;
xassert (!STRINGP (it->string));
if (it->stop_charpos >= limit
|| ((pos = Fnext_single_property_change (make_number (start),
Qdisplay,
Qnil, make_number (limit)),
NILP (pos))
&& next_overlay_change (start) == ZV))
{
IT_CHARPOS (*it) = limit;
IT_BYTEPOS (*it) = CHAR_TO_BYTE (limit);
*skipped_p = newline_found_p = 1;
}
else
{
while (get_next_display_element (it)
&& !newline_found_p)
{
newline_found_p = ITERATOR_AT_END_OF_LINE_P (it);
set_iterator_to_next (it, 0);
}
}
}
it->selective = old_selective;
return newline_found_p;
}
static void
back_to_previous_visible_line_start (it)
struct it *it;
{
int visible_p = 0;
if (IT_CHARPOS (*it) > BEGV)
back_to_previous_line_start (it);
while (IT_CHARPOS (*it) > BEGV
&& !visible_p)
{
visible_p = 1;
if (it->selective > 0
&& indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
it->selective))
visible_p = 0;
else
{
Lisp_Object prop;
prop = Fget_char_property (make_number (IT_CHARPOS (*it)),
Qinvisible, it->window);
if (TEXT_PROP_MEANS_INVISIBLE (prop))
visible_p = 0;
}
if (!visible_p)
back_to_previous_line_start (it);
}
xassert (IT_CHARPOS (*it) >= BEGV);
xassert (IT_CHARPOS (*it) == BEGV
|| FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
CHECK_IT (it);
}
static void
reseat_at_previous_visible_line_start (it)
struct it *it;
{
back_to_previous_visible_line_start (it);
reseat (it, it->current.pos, 1);
CHECK_IT (it);
}
static void
reseat_at_next_visible_line_start (it, on_newline_p)
struct it *it;
int on_newline_p;
{
int newline_found_p, skipped_p = 0;
newline_found_p = forward_to_next_line_start (it, &skipped_p);
if (it->selective > 0)
while (IT_CHARPOS (*it) < ZV
&& indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
it->selective))
{
xassert (FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
newline_found_p = forward_to_next_line_start (it, &skipped_p);
}
if (on_newline_p && newline_found_p)
{
if (STRINGP (it->string))
{
if (IT_STRING_CHARPOS (*it) > 0)
{
--IT_STRING_CHARPOS (*it);
--IT_STRING_BYTEPOS (*it);
}
}
else if (IT_CHARPOS (*it) > BEGV)
{
--IT_CHARPOS (*it);
--IT_BYTEPOS (*it);
reseat (it, it->current.pos, 0);
}
}
else if (skipped_p)
reseat (it, it->current.pos, 0);
CHECK_IT (it);
}
static void
reseat (it, pos, force_p)
struct it *it;
struct text_pos pos;
int force_p;
{
int original_pos = IT_CHARPOS (*it);
reseat_1 (it, pos, 0);
if (force_p
|| CHARPOS (pos) > it->stop_charpos
|| CHARPOS (pos) < original_pos)
handle_stop (it);
CHECK_IT (it);
}
static void
reseat_1 (it, pos, set_stop_p)
struct it *it;
struct text_pos pos;
int set_stop_p;
{
xassert (it->s == NULL);
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->current.overlay_string_index = -1;
IT_STRING_CHARPOS (*it) = -1;
IT_STRING_BYTEPOS (*it) = -1;
it->string = Qnil;
it->method = next_element_from_buffer;
it->multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
it->sp = 0;
it->face_before_selective_p = 0;
if (set_stop_p)
it->stop_charpos = CHARPOS (pos);
}
static void
reseat_to_string (it, s, string, charpos, precision, field_width, multibyte)
struct it *it;
unsigned char *s;
Lisp_Object string;
int charpos;
int precision, field_width, multibyte;
{
it->region_beg_charpos = it->region_end_charpos = -1;
it->stop_charpos = -1;
bzero (&it->current, sizeof it->current);
it->current.overlay_string_index = -1;
it->current.dpvec_index = -1;
xassert (charpos >= 0);
if (multibyte >= 0)
it->multibyte_p = multibyte > 0;
if (s == NULL)
{
xassert (STRINGP (string));
it->string = string;
it->s = NULL;
it->end_charpos = it->string_nchars = XSTRING (string)->size;
it->method = next_element_from_string;
it->current.string_pos = string_pos (charpos, string);
}
else
{
it->s = s;
it->string = Qnil;
IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1;
if (it->multibyte_p)
{
it->current.pos = c_string_pos (charpos, s, 1);
it->end_charpos = it->string_nchars = number_of_chars (s, 1);
}
else
{
IT_CHARPOS (*it) = IT_BYTEPOS (*it) = charpos;
it->end_charpos = it->string_nchars = strlen (s);
}
it->method = next_element_from_c_string;
}
if (precision > 0 && it->end_charpos - charpos > precision)
it->end_charpos = it->string_nchars = charpos + precision;
if (field_width < 0)
field_width = INFINITY;
if (field_width > it->end_charpos - charpos)
it->end_charpos = charpos + field_width;
if (DISP_TABLE_P (Vstandard_display_table))
it->dp = XCHAR_TABLE (Vstandard_display_table);
it->stop_charpos = charpos;
CHECK_IT (it);
}
int
get_next_display_element (it)
struct it *it;
{
int success_p = (*it->method) (it);
if (it->what == IT_CHARACTER)
{
if (success_p && it->dpvec == NULL)
{
Lisp_Object dv;
if (it->dp
&& (dv = DISP_CHAR_VECTOR (it->dp, it->c),
VECTORP (dv)))
{
struct Lisp_Vector *v = XVECTOR (dv);
if (v->size)
{
it->dpvec_char_len = it->len;
it->dpvec = v->contents;
it->dpend = v->contents + v->size;
it->current.dpvec_index = 0;
it->method = next_element_from_display_vector;
success_p = get_next_display_element (it);
}
else
{
set_iterator_to_next (it, 0);
success_p = get_next_display_element (it);
}
}
else if ((it->c < ' '
&& (it->area != TEXT_AREA
|| (it->c != '\n' && it->c != '\t')))
|| (it->c >= 127
&& it->len == 1)
|| !CHAR_PRINTABLE_P (it->c))
{
GLYPH g;
if (it->c < 128 && it->ctl_arrow_p)
{
if (it->dp
&& INTEGERP (DISP_CTRL_GLYPH (it->dp))
&& GLYPH_CHAR_VALID_P (XINT (DISP_CTRL_GLYPH (it->dp))))
g = XINT (DISP_CTRL_GLYPH (it->dp));
else
g = FAST_MAKE_GLYPH ('^', 0);
XSETINT (it->ctl_chars[0], g);
g = FAST_MAKE_GLYPH (it->c ^ 0100, 0);
XSETINT (it->ctl_chars[1], g);
it->dpvec_char_len = it->len;
it->dpvec = it->ctl_chars;
it->dpend = it->dpvec + 2;
it->current.dpvec_index = 0;
it->method = next_element_from_display_vector;
get_next_display_element (it);
}
else
{
unsigned char str[MAX_MULTIBYTE_LENGTH];
int len;
int i;
GLYPH 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));
else
escape_glyph = FAST_MAKE_GLYPH ('\\', 0);
if (SINGLE_BYTE_CHAR_P (it->c))
str[0] = it->c, len = 1;
else
{
len = CHAR_STRING_NO_SIGNAL (it->c, str);
if (len < 0)
{
str[0] = it->c;
str[1] = it->c >> 8;
str[2] = it->c >> 16;
str[3] = it->c >> 24;
len = 4;
}
}
for (i = 0; i < len; i++)
{
XSETINT (it->ctl_chars[i * 4], escape_glyph);
g = FAST_MAKE_GLYPH (((str[i] >> 6) & 7) + '0', 0);
XSETINT (it->ctl_chars[i * 4 + 1], g);
g = FAST_MAKE_GLYPH (((str[i] >> 3) & 7) + '0', 0);
XSETINT (it->ctl_chars[i * 4 + 2], g);
g = FAST_MAKE_GLYPH ((str[i] & 7) + '0', 0);
XSETINT (it->ctl_chars[i * 4 + 3], g);
}
it->dpvec_char_len = it->len;
it->dpvec = it->ctl_chars;
it->dpend = it->dpvec + len * 4;
it->current.dpvec_index = 0;
it->method = next_element_from_display_vector;
get_next_display_element (it);
}
}
}
if (it->multibyte_p
&& success_p
&& FRAME_WINDOW_P (it->f))
{
struct face *face = FACE_FROM_ID (it->f, it->face_id);
it->face_id = FACE_FOR_CHAR (it->f, face, it->c);
}
}
if (it->face_box_p
&& it->s == NULL)
{
int face_id;
struct face *face;
it->end_of_box_run_p
= ((face_id = face_after_it_pos (it),
face_id != it->face_id)
&& (face = FACE_FROM_ID (it->f, face_id),
face->box == FACE_NO_BOX));
}
return success_p;
}
void
set_iterator_to_next (it, reseat_p)
struct it *it;
int reseat_p;
{
it->start_of_box_run_p = it->end_of_box_run_p = 0;
if (it->method == next_element_from_buffer)
{
if (ITERATOR_AT_END_OF_LINE_P (it) && reseat_p)
reseat_at_next_visible_line_start (it, 0);
else
{
xassert (it->len != 0);
IT_BYTEPOS (*it) += it->len;
IT_CHARPOS (*it) += 1;
xassert (IT_BYTEPOS (*it) == CHAR_TO_BYTE (IT_CHARPOS (*it)));
}
}
else if (it->method == next_element_from_composition)
{
xassert (it->cmp_id >= 0 && it ->cmp_id < n_compositions);
if (STRINGP (it->string))
{
IT_STRING_BYTEPOS (*it) += it->len;
IT_STRING_CHARPOS (*it) += it->cmp_len;
it->method = next_element_from_string;
goto consider_string_end;
}
else
{
IT_BYTEPOS (*it) += it->len;
IT_CHARPOS (*it) += it->cmp_len;
it->method = next_element_from_buffer;
}
}
else if (it->method == next_element_from_c_string)
{
IT_BYTEPOS (*it) += it->len;
IT_CHARPOS (*it) += 1;
}
else if (it->method == next_element_from_display_vector)
{
++it->current.dpvec_index;
it->face_id = it->saved_face_id;
if (it->dpvec + it->current.dpvec_index == it->dpend)
{
if (it->s)
it->method = next_element_from_c_string;
else if (STRINGP (it->string))
it->method = next_element_from_string;
else
it->method = next_element_from_buffer;
it->dpvec = NULL;
it->current.dpvec_index = -1;
if (it->dpvec_char_len < 0)
reseat_at_next_visible_line_start (it, 1);
else if (it->dpvec_char_len > 0)
{
it->len = it->dpvec_char_len;
set_iterator_to_next (it, reseat_p);
}
}
}
else if (it->method == next_element_from_string)
{
xassert (it->s == NULL && STRINGP (it->string));
IT_STRING_BYTEPOS (*it) += it->len;
IT_STRING_CHARPOS (*it) += 1;
consider_string_end:
if (it->current.overlay_string_index >= 0)
{
if (IT_STRING_CHARPOS (*it) >= XSTRING (it->string)->size)
next_overlay_string (it);
}
else
{
if (IT_STRING_CHARPOS (*it) == XSTRING (it->string)->size
&& it->sp > 0)
{
pop_it (it);
if (!STRINGP (it->string))
it->method = next_element_from_buffer;
else
goto consider_string_end;
}
}
}
else if (it->method == next_element_from_image
|| it->method == next_element_from_stretch)
{
pop_it (it);
it->image_id = 0;
if (STRINGP (it->string))
{
it->method = next_element_from_string;
goto consider_string_end;
}
else
it->method = next_element_from_buffer;
}
else
abort ();
xassert (it->method != next_element_from_string
|| (STRINGP (it->string)
&& IT_STRING_CHARPOS (*it) >= 0));
}
static int
next_element_from_display_vector (it)
struct it *it;
{
xassert (it->dpvec && it->current.dpvec_index >= 0);
it->saved_face_id = it->face_id;
if (INTEGERP (*it->dpvec)
&& GLYPH_CHAR_VALID_P (XFASTINT (*it->dpvec)))
{
int lface_id;
GLYPH g;
g = XFASTINT (it->dpvec[it->current.dpvec_index]);
it->c = FAST_GLYPH_CHAR (g);
it->len = CHAR_BYTES (it->c);
lface_id = FAST_GLYPH_FACE (g);
if (lface_id)
{
int face_id = ascii_face_of_lisp_face (it->f, lface_id);
if (face_id >= 0)
it->face_id = face_id;
}
}
else
it->c = ' ', it->len = 1;
it->what = IT_CHARACTER;
return 1;
}
static int
next_element_from_string (it)
struct it *it;
{
struct text_pos position;
xassert (STRINGP (it->string));
xassert (IT_STRING_CHARPOS (*it) >= 0);
position = it->current.string_pos;
if (IT_STRING_CHARPOS (*it) < it->end_charpos
&& IT_STRING_CHARPOS (*it) == it->stop_charpos)
{
handle_stop (it);
return get_next_display_element (it);
}
if (it->current.overlay_string_index >= 0)
{
if (IT_STRING_CHARPOS (*it) >= XSTRING (it->string)->size)
{
it->what = IT_EOB;
return 0;
}
else if (STRING_MULTIBYTE (it->string))
{
int remaining = (STRING_BYTES (XSTRING (it->string))
- IT_STRING_BYTEPOS (*it));
unsigned char *s = (XSTRING (it->string)->data
+ IT_STRING_BYTEPOS (*it));
it->c = string_char_and_length (s, remaining, &it->len);
}
else
{
it->c = XSTRING (it->string)->data[IT_STRING_BYTEPOS (*it)];
it->len = 1;
}
}
else
{
if (IT_STRING_CHARPOS (*it) >= it->end_charpos)
{
it->what = IT_EOB;
return 0;
}
else if (IT_STRING_CHARPOS (*it) >= it->string_nchars)
{
it->c = ' ', it->len = 1;
CHARPOS (position) = BYTEPOS (position) = -1;
}
else if (STRING_MULTIBYTE (it->string))
{
int maxlen = (STRING_BYTES (XSTRING (it->string))
- IT_STRING_BYTEPOS (*it));
unsigned char *s = (XSTRING (it->string)->data
+ IT_STRING_BYTEPOS (*it));
it->c = string_char_and_length (s, maxlen, &it->len);
}
else
{
it->c = XSTRING (it->string)->data[IT_STRING_BYTEPOS (*it)];
it->len = 1;
}
}
it->what = IT_CHARACTER;
it->object = it->string;
it->position = position;
return 1;
}
static int
next_element_from_c_string (it)
struct it *it;
{
int success_p = 1;
xassert (it->s);
it->what = IT_CHARACTER;
BYTEPOS (it->position) = CHARPOS (it->position) = 0;
it->object = Qnil;
if (IT_CHARPOS (*it) >= it->end_charpos)
{
it->what = IT_EOB;
success_p = 0;
}
else if (IT_CHARPOS (*it) >= it->string_nchars)
{
it->c = ' ', it->len = 1;
BYTEPOS (it->position) = CHARPOS (it->position) = -1;
}
else if (it->multibyte_p)
{
int maxlen = strlen (it->s) - IT_BYTEPOS (*it);
it->c = string_char_and_length (it->s + IT_BYTEPOS (*it),
maxlen, &it->len);
}
else
it->c = it->s[IT_BYTEPOS (*it)], it->len = 1;
return success_p;
}
static int
next_element_from_ellipsis (it)
struct it *it;
{
if (it->selective_display_ellipsis_p)
{
if (it->dp && VECTORP (DISP_INVIS_VECTOR (it->dp)))
{
struct Lisp_Vector *v = XVECTOR (DISP_INVIS_VECTOR (it->dp));
it->dpvec_char_len = it->len;
it->dpvec = v->contents;
it->dpend = v->contents + v->size;
it->current.dpvec_index = 0;
it->method = next_element_from_display_vector;
}
else
{
it->dpvec_char_len = it->len;
it->dpvec = default_invis_vector;
it->dpend = default_invis_vector + 3;
it->current.dpvec_index = 0;
it->method = next_element_from_display_vector;
}
}
else
{
it->saved_face_id = it->face_id;
it->method = next_element_from_buffer;
reseat_at_next_visible_line_start (it, 1);
it->face_before_selective_p = 1;
}
return get_next_display_element (it);
}
static int
next_element_from_image (it)
struct it *it;
{
it->what = IT_IMAGE;
return 1;
}
static int
next_element_from_stretch (it)
struct it *it;
{
it->what = IT_STRETCH;
return 1;
}
static int
next_element_from_buffer (it)
struct it *it;
{
int success_p = 1;
xassert (IT_CHARPOS (*it) >= BEGV
&& IT_CHARPOS (*it) <= it->stop_charpos);
if (IT_CHARPOS (*it) >= it->stop_charpos)
{
if (IT_CHARPOS (*it) >= it->end_charpos)
{
int overlay_strings_follow_p;
if (it->overlay_strings_at_end_processed_p)
overlay_strings_follow_p = 0;
else
{
it->overlay_strings_at_end_processed_p = 1;
overlay_strings_follow_p = get_overlay_strings (it, 0);
}
if (overlay_strings_follow_p)
success_p = get_next_display_element (it);
else
{
it->what = IT_EOB;
it->position = it->current.pos;
success_p = 0;
}
}
else
{
handle_stop (it);
return get_next_display_element (it);
}
}
else
{
unsigned char *p;
if (it->redisplay_end_trigger_charpos
&& it->glyph_row
&& IT_CHARPOS (*it) >= it->redisplay_end_trigger_charpos)
run_redisplay_end_trigger_hook (it);
p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
if (it->multibyte_p && !ASCII_BYTE_P (*p))
{
int maxlen = ((IT_BYTEPOS (*it) >= GPT_BYTE ? ZV_BYTE : GPT_BYTE)
- IT_BYTEPOS (*it));
it->c = string_char_and_length (p, maxlen, &it->len);
}
else
it->c = *p, it->len = 1;
it->what = IT_CHARACTER;;
it->object = it->w->buffer;
it->position = it->current.pos;
if (it->selective)
{
if (it->c == '\n')
{
if (it->selective > 0
&& IT_CHARPOS (*it) + 1 < ZV
&& indented_beyond_p (IT_CHARPOS (*it) + 1,
IT_BYTEPOS (*it) + 1,
it->selective))
{
success_p = next_element_from_ellipsis (it);
it->dpvec_char_len = -1;
}
}
else if (it->c == '\r' && it->selective == -1)
{
success_p = next_element_from_ellipsis (it);
it->dpvec_char_len = -1;
}
}
}
xassert (!success_p || it->what != IT_CHARACTER || it->len > 0);
return success_p;
}
static void
run_redisplay_end_trigger_hook (it)
struct it *it;
{
Lisp_Object args[3];
xassert (it->glyph_row);
args[0] = Qredisplay_end_trigger_functions;
args[1] = it->window;
XSETINT (args[2], it->redisplay_end_trigger_charpos);
it->redisplay_end_trigger_charpos = 0;
it->w->redisplay_end_trigger = Qnil;
Frun_hook_with_args (3, args);
handle_face_prop (it);
}
static int
next_element_from_composition (it)
struct it *it;
{
it->what = IT_COMPOSITION;
it->position = (STRINGP (it->string)
? it->current.string_pos
: it->current.pos);
return 1;
}
static enum move_it_result
move_it_in_display_line_to (it, to_charpos, to_x, op)
struct it *it;
int to_charpos, to_x, op;
{
enum move_it_result result = MOVE_UNDEFINED;
struct glyph_row *saved_glyph_row;
saved_glyph_row = it->glyph_row;
it->glyph_row = NULL;
while (1)
{
int x, i, ascent = 0, descent = 0;
if (!get_next_display_element (it)
|| ((op & MOVE_TO_POS) != 0
&& BUFFERP (it->object)
&& IT_CHARPOS (*it) >= to_charpos))
{
result = MOVE_POS_MATCH_OR_ZV;
break;
}
x = it->current_x;
if (!it->truncate_lines_p)
{
ascent = it->max_ascent;
descent = it->max_descent;
}
PRODUCE_GLYPHS (it);
if (it->area != TEXT_AREA)
{
set_iterator_to_next (it, 1);
continue;
}
if (it->nglyphs)
{
int single_glyph_width = it->pixel_width / it->nglyphs;
int new_x;
for (i = 0; i < it->nglyphs; ++i, x = new_x)
{
new_x = x + single_glyph_width;
if ((op & MOVE_TO_X) && new_x > to_x)
{
it->current_x = x;
result = MOVE_X_REACHED;
break;
}
else if (
!it->truncate_lines_p
&& (
new_x > it->last_visible_x
|| (new_x == it->last_visible_x
&& FRAME_WINDOW_P (it->f))))
{
if (
it->hpos == 0
|| (new_x == it->last_visible_x
&& FRAME_WINDOW_P (it->f)))
{
++it->hpos;
it->current_x = new_x;
if (i == it->nglyphs - 1)
set_iterator_to_next (it, 1);
}
else
{
it->current_x = x;
it->max_ascent = ascent;
it->max_descent = descent;
}
TRACE_MOVE ((stderr, "move_it_in: continued at %d\n",
IT_CHARPOS (*it)));
result = MOVE_LINE_CONTINUED;
break;
}
else if (new_x > it->first_visible_x)
{
++it->hpos;
}
else
{
}
}
if (result != MOVE_UNDEFINED)
break;
}
else if ((op & MOVE_TO_X) && it->current_x >= to_x)
{
xassert (it->nglyphs == 0);
result = MOVE_X_REACHED;
break;
}
if (ITERATOR_AT_END_OF_LINE_P (it))
{
result = MOVE_NEWLINE_OR_CR;
break;
}
set_iterator_to_next (it, 1);
if (it->truncate_lines_p
&& it->current_x >= it->last_visible_x)
{
result = MOVE_LINE_TRUNCATED;
break;
}
}
it->glyph_row = saved_glyph_row;
return result;
}
void
move_it_to (it, to_charpos, to_x, to_y, to_vpos, op)
struct it *it;
int to_charpos, to_x, to_y, to_vpos;
int op;
{
enum move_it_result skip, skip2 = MOVE_X_REACHED;
int line_height;
int reached = 0;
for (;;)
{
if (op & MOVE_TO_VPOS)
{
if ((op & (MOVE_TO_X | MOVE_TO_POS)) == 0)
{
if (it->vpos == to_vpos)
{
reached = 1;
break;
}
else
skip = move_it_in_display_line_to (it, -1, -1, 0);
}
else
{
if (it->vpos == to_vpos)
{
reached = 2;
break;
}
skip = move_it_in_display_line_to (it, to_charpos, to_x, op);
if (skip == MOVE_POS_MATCH_OR_ZV || it->vpos == to_vpos)
{
reached = 3;
break;
}
else if (skip == MOVE_X_REACHED && it->vpos != to_vpos)
{
skip = move_it_in_display_line_to (it, to_charpos,
-1, MOVE_TO_POS);
if (skip == MOVE_POS_MATCH_OR_ZV)
{
reached = 4;
break;
}
}
}
}
else if (op & MOVE_TO_Y)
{
struct it it_backup;
skip = move_it_in_display_line_to (it, to_charpos,
((op & MOVE_TO_X)
? to_x : 0),
(MOVE_TO_X
| (op & MOVE_TO_POS)));
if (skip == MOVE_POS_MATCH_OR_ZV)
{
reached = 5;
break;
}
if (skip == MOVE_X_REACHED)
{
it_backup = *it;
TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it)));
skip2 = move_it_in_display_line_to (it, to_charpos, -1,
op & MOVE_TO_POS);
TRACE_MOVE ((stderr, "move_it: to %d\n", IT_CHARPOS (*it)));
}
line_height = it->max_ascent + it->max_descent;
TRACE_MOVE ((stderr, "move_it: line_height = %d\n", line_height));
if (to_y >= it->current_y
&& to_y < it->current_y + line_height)
{
if (skip == MOVE_X_REACHED)
*it = it_backup;
reached = 6;
}
else if (skip == MOVE_X_REACHED)
{
skip = skip2;
if (skip == MOVE_POS_MATCH_OR_ZV)
reached = 7;
}
if (reached)
break;
}
else
skip = move_it_in_display_line_to (it, to_charpos, -1, MOVE_TO_POS);
switch (skip)
{
case MOVE_POS_MATCH_OR_ZV:
reached = 8;
goto out;
case MOVE_NEWLINE_OR_CR:
set_iterator_to_next (it, 1);
it->continuation_lines_width = 0;
break;
case MOVE_LINE_TRUNCATED:
it->continuation_lines_width = 0;
reseat_at_next_visible_line_start (it, 0);
if ((op & MOVE_TO_POS) != 0
&& IT_CHARPOS (*it) > to_charpos)
{
reached = 9;
goto out;
}
break;
case MOVE_LINE_CONTINUED:
it->continuation_lines_width += it->current_x;
break;
default:
abort ();
}
recenter_overlay_lists (current_buffer, IT_CHARPOS (*it));
it->current_x = it->hpos = 0;
it->current_y += it->max_ascent + it->max_descent;
++it->vpos;
last_height = it->max_ascent + it->max_descent;
last_max_ascent = it->max_ascent;
it->max_ascent = it->max_descent = 0;
}
out:
TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached));
}
void
move_it_vertically_backward (it, dy)
struct it *it;
int dy;
{
int nlines, h;
struct it it2, it3;
int start_pos = IT_CHARPOS (*it);
xassert (dy >= 0);
nlines = max (1, dy / CANON_Y_UNIT (it->f));
while (nlines-- && IT_CHARPOS (*it) > BEGV)
back_to_previous_visible_line_start (it);
reseat_1 (it, it->current.pos, 1);
it->current_x = it->hpos = 0;
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);
xassert (IT_CHARPOS (*it) >= BEGV);
it3 = it2;
move_it_to (&it2, start_pos, -1, -1, -1, MOVE_TO_POS);
xassert (IT_CHARPOS (*it) >= BEGV);
h = it2.current_y - it->current_y;
nlines = it2.vpos - it->vpos;
it->vpos -= nlines;
it->current_y -= h;
if (dy == 0)
{
if (nlines > 0)
move_it_by_lines (it, nlines, 1);
xassert (IT_CHARPOS (*it) <= start_pos);
}
else if (nlines)
{
int target_y = it->current_y + h - dy;
int y0 = it3.current_y;
int y1 = line_bottom_y (&it3);
int line_height = y1 - y0;
if (target_y < it->current_y
&& it->current_y - target_y > line_height / 3 * 2
&& IT_CHARPOS (*it) > BEGV)
{
TRACE_MOVE ((stderr, " not far enough -> move_vert %d\n",
target_y - it->current_y));
move_it_vertically (it, target_y - it->current_y);
xassert (IT_CHARPOS (*it) >= BEGV);
}
else if (target_y >= it->current_y + line_height
&& IT_CHARPOS (*it) < ZV)
{
if (!FRAME_WINDOW_P (it->f))
move_it_vertically (it, target_y - (it->current_y + line_height));
else
{
do
{
move_it_by_lines (it, 1, 1);
}
while (target_y >= line_bottom_y (it) && IT_CHARPOS (*it) < ZV);
}
xassert (IT_CHARPOS (*it) >= BEGV);
}
}
}
void
move_it_vertically (it, dy)
struct it *it;
int dy;
{
if (dy <= 0)
move_it_vertically_backward (it, -dy);
else if (dy > 0)
{
TRACE_MOVE ((stderr, "move_it_v: from %d, %d\n", IT_CHARPOS (*it), dy));
move_it_to (it, ZV, -1, it->current_y + dy, -1,
MOVE_TO_POS | MOVE_TO_Y);
TRACE_MOVE ((stderr, "move_it_v: to %d\n", IT_CHARPOS (*it)));
if (IT_CHARPOS (*it) == ZV
&& FETCH_BYTE (IT_BYTEPOS (*it) - 1) != '\n')
move_it_by_lines (it, 0, 0);
}
}
void
move_it_past_eol (it)
struct it *it;
{
enum move_it_result rc;
rc = move_it_in_display_line_to (it, Z, 0, MOVE_TO_POS);
if (rc == MOVE_NEWLINE_OR_CR)
set_iterator_to_next (it, 0);
}
#if 0
static int
invisible_text_between_p (it, start_charpos, end_charpos)
struct it *it;
int start_charpos, end_charpos;
{
Lisp_Object prop, limit;
int invisible_found_p;
xassert (it != NULL && start_charpos <= end_charpos);
prop = Fget_char_property (make_number (start_charpos), Qinvisible,
it->window);
if (TEXT_PROP_MEANS_INVISIBLE (prop))
invisible_found_p = 1;
else
{
limit = Fnext_single_char_property_change (make_number (start_charpos),
Qinvisible, Qnil,
make_number (end_charpos));
invisible_found_p = XFASTINT (limit) < end_charpos;
}
return invisible_found_p;
}
#endif
void
move_it_by_lines (it, dvpos, need_y_p)
struct it *it;
int dvpos, need_y_p;
{
struct position pos;
if (!FRAME_WINDOW_P (it->f))
{
struct text_pos textpos;
pos = *vmotion (IT_CHARPOS (*it), dvpos, it->w);
SET_TEXT_POS (textpos, pos.bufpos, pos.bytepos);
reseat (it, textpos, 1);
it->vpos += pos.vpos;
it->current_y += pos.vpos;
}
else if (dvpos == 0)
{
move_it_vertically_backward (it, 0);
xassert (it->current_x == 0 && it->hpos == 0);
}
else if (dvpos > 0)
move_it_to (it, -1, -1, -1, it->vpos + dvpos, MOVE_TO_VPOS);
else
{
struct it it2;
int start_charpos, i;
move_it_vertically_backward (it, 0);
start_charpos = IT_CHARPOS (*it);
for (i = -dvpos; i && IT_CHARPOS (*it) > BEGV; --i)
back_to_previous_visible_line_start (it);
reseat (it, it->current.pos, 1);
it->current_x = it->hpos = 0;
it2 = *it;
it2.vpos = it2.current_y = 0;
move_it_to (&it2, start_charpos, -1, -1, -1, MOVE_TO_POS);
it->vpos -= it2.vpos;
it->current_y -= it2.current_y;
it->current_x = it->hpos = 0;
if (it2.vpos > -dvpos)
{
int delta = it2.vpos + dvpos;
move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS);
}
}
}
void
add_to_log (format, arg1, arg2)
char *format;
Lisp_Object arg1, arg2;
{
Lisp_Object args[3];
Lisp_Object msg, fmt;
char *buffer;
int len;
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
if (handling_signal)
return;
fmt = msg = Qnil;
GCPRO4 (fmt, msg, arg1, arg2);
args[0] = fmt = build_string (format);
args[1] = arg1;
args[2] = arg2;
msg = Fformat (3, args);
len = STRING_BYTES (XSTRING (msg)) + 1;
buffer = (char *) alloca (len);
bcopy (XSTRING (msg)->data, buffer, len);
message_dolog (buffer, len - 1, 1, 0);
UNGCPRO;
}
void
message_log_maybe_newline ()
{
if (message_log_need_newline)
message_dolog ("", 0, 1, 0);
}
void
message_dolog (m, nbytes, nlflag, multibyte)
char *m;
int nbytes, nlflag, multibyte;
{
if (!NILP (Vmessage_log_max))
{
struct buffer *oldbuf;
Lisp_Object oldpoint, oldbegv, oldzv;
int old_windows_or_buffers_changed = windows_or_buffers_changed;
int point_at_end = 0;
int zv_at_end = 0;
Lisp_Object old_deactivate_mark, tem;
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
old_deactivate_mark = Vdeactivate_mark;
oldbuf = current_buffer;
Fset_buffer (Fget_buffer_create (Vmessages_buffer_name));
current_buffer->undo_list = Qt;
oldpoint = Fpoint_marker ();
oldbegv = Fpoint_min_marker ();
oldzv = Fpoint_max_marker ();
GCPRO4 (oldpoint, oldbegv, oldzv, old_deactivate_mark);
if (PT == Z)
point_at_end = 1;
if (ZV == Z)
zv_at_end = 1;
BEGV = BEG;
BEGV_BYTE = BEG_BYTE;
ZV = Z;
ZV_BYTE = Z_BYTE;
TEMP_SET_PT_BOTH (Z, Z_BYTE);
if (multibyte
&& NILP (current_buffer->enable_multibyte_characters))
{
int i, c, char_bytes;
unsigned char work[1];
for (i = 0; i < nbytes; i += nbytes)
{
c = string_char_and_length (m + i, nbytes - i, &char_bytes);
work[0] = (SINGLE_BYTE_CHAR_P (c)
? c
: multibyte_char_to_unibyte (c, Qnil));
insert_1_both (work, 1, 1, 1, 0, 0);
}
}
else if (! multibyte
&& ! NILP (current_buffer->enable_multibyte_characters))
{
int i, c, char_bytes;
unsigned char *msg = (unsigned char *) m;
unsigned char str[MAX_MULTIBYTE_LENGTH];
for (i = 0; i < nbytes; i++)
{
c = unibyte_char_to_multibyte (msg[i]);
char_bytes = CHAR_STRING (c, str);
insert_1_both (str, 1, char_bytes, 1, 0, 0);
}
}
else if (nbytes)
insert_1 (m, nbytes, 1, 0, 0);
if (nlflag)
{
int this_bol, this_bol_byte, prev_bol, prev_bol_byte, dup;
insert_1 ("\n", 1, 1, 0, 0);
scan_newline (Z, Z_BYTE, BEG, BEG_BYTE, -2, 0);
this_bol = PT;
this_bol_byte = PT_BYTE;
if (this_bol > BEG)
{
scan_newline (PT, PT_BYTE, BEG, BEG_BYTE, -2, 0);
prev_bol = PT;
prev_bol_byte = PT_BYTE;
dup = message_log_check_duplicate (prev_bol, prev_bol_byte,
this_bol, this_bol_byte);
if (dup)
{
del_range_both (prev_bol, prev_bol_byte,
this_bol, this_bol_byte, 0);
if (dup > 1)
{
char dupstr[40];
int duplen;
sprintf (dupstr, " [%d times]", dup);
duplen = strlen (dupstr);
TEMP_SET_PT_BOTH (Z - 1, Z_BYTE - 1);
insert_1 (dupstr, duplen, 1, 0, 1);
}
}
}
if (NATNUMP (Vmessage_log_max))
{
scan_newline (Z, Z_BYTE, BEG, BEG_BYTE,
-XFASTINT (Vmessage_log_max) - 1, 0);
del_range_both (BEG, BEG_BYTE, PT, PT_BYTE, 0);
}
}
BEGV = XMARKER (oldbegv)->charpos;
BEGV_BYTE = marker_byte_position (oldbegv);
if (zv_at_end)
{
ZV = Z;
ZV_BYTE = Z_BYTE;
}
else
{
ZV = XMARKER (oldzv)->charpos;
ZV_BYTE = marker_byte_position (oldzv);
}
if (point_at_end)
TEMP_SET_PT_BOTH (Z, Z_BYTE);
else
TEMP_SET_PT_BOTH (XMARKER (oldpoint)->charpos,
XMARKER (oldpoint)->bytepos);
UNGCPRO;
free_marker (oldpoint);
free_marker (oldbegv);
free_marker (oldzv);
tem = Fget_buffer_window (Fcurrent_buffer (), Qt);
set_buffer_internal (oldbuf);
if (NILP (tem))
windows_or_buffers_changed = old_windows_or_buffers_changed;
message_log_need_newline = !nlflag;
Vdeactivate_mark = old_deactivate_mark;
}
}
static int
message_log_check_duplicate (prev_bol, prev_bol_byte, this_bol, this_bol_byte)
int prev_bol, this_bol;
int prev_bol_byte, this_bol_byte;
{
int i;
int len = Z_BYTE - 1 - this_bol_byte;
int seen_dots = 0;
unsigned char *p1 = BUF_BYTE_ADDRESS (current_buffer, prev_bol_byte);
unsigned char *p2 = BUF_BYTE_ADDRESS (current_buffer, this_bol_byte);
for (i = 0; i < len; i++)
{
if (i >= 3 && p1[i-3] == '.' && p1[i-2] == '.' && p1[i-1] == '.')
seen_dots = 1;
if (p1[i] != p2[i])
return seen_dots;
}
p1 += len;
if (*p1 == '\n')
return 2;
if (*p1++ == ' ' && *p1++ == '[')
{
int n = 0;
while (*p1 >= '0' && *p1 <= '9')
n = n * 10 + *p1++ - '0';
if (strncmp (p1, " times]\n", 8) == 0)
return n+1;
}
return 0;
}
void
message2 (m, nbytes, multibyte)
char *m;
int nbytes;
int multibyte;
{
message_log_maybe_newline ();
if (m)
message_dolog (m, nbytes, 1, multibyte);
message2_nolog (m, nbytes, multibyte);
}
void
message2_nolog (m, nbytes, multibyte)
char *m;
int nbytes;
{
struct frame *sf = SELECTED_FRAME ();
message_enable_multibyte = multibyte;
if (noninteractive)
{
if (noninteractive_need_newline)
putc ('\n', stderr);
noninteractive_need_newline = 0;
if (m)
fwrite (m, nbytes, 1, stderr);
if (cursor_in_echo_area == 0)
fprintf (stderr, "\n");
fflush (stderr);
}
else if (INTERACTIVE
&& sf->glyphs_initialized_p
&& FRAME_MESSAGE_BUF (sf))
{
Lisp_Object mini_window;
struct frame *f;
mini_window = FRAME_MINIBUF_WINDOW (sf);
f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
FRAME_SAMPLE_VISIBILITY (f);
if (FRAME_VISIBLE_P (sf)
&& ! FRAME_VISIBLE_P (f))
Fmake_frame_visible (WINDOW_FRAME (XWINDOW (mini_window)));
if (m)
{
set_message (m, Qnil, nbytes, multibyte);
if (minibuffer_auto_raise)
Fraise_frame (WINDOW_FRAME (XWINDOW (mini_window)));
}
else
clear_message (1, 1);
do_pending_window_change (0);
echo_area_display (1);
do_pending_window_change (0);
if (frame_up_to_date_hook != 0 && ! gc_in_progress)
(*frame_up_to_date_hook) (f);
}
}
void
message3 (m, nbytes, multibyte)
Lisp_Object m;
int nbytes;
int multibyte;
{
struct gcpro gcpro1;
GCPRO1 (m);
message_log_maybe_newline ();
if (STRINGP (m))
message_dolog (XSTRING (m)->data, nbytes, 1, multibyte);
message3_nolog (m, nbytes, multibyte);
UNGCPRO;
}
void
message3_nolog (m, nbytes, multibyte)
Lisp_Object m;
int nbytes, multibyte;
{
struct frame *sf = SELECTED_FRAME ();
message_enable_multibyte = multibyte;
if (noninteractive)
{
if (noninteractive_need_newline)
putc ('\n', stderr);
noninteractive_need_newline = 0;
if (STRINGP (m))
fwrite (XSTRING (m)->data, nbytes, 1, stderr);
if (cursor_in_echo_area == 0)
fprintf (stderr, "\n");
fflush (stderr);
}
else if (INTERACTIVE
&& sf->glyphs_initialized_p
&& FRAME_MESSAGE_BUF (sf))
{
Lisp_Object mini_window;
Lisp_Object frame;
struct frame *f;
mini_window = FRAME_MINIBUF_WINDOW (sf);
frame = XWINDOW (mini_window)->frame;
f = XFRAME (frame);
FRAME_SAMPLE_VISIBILITY (f);
if (FRAME_VISIBLE_P (sf)
&& !FRAME_VISIBLE_P (f))
Fmake_frame_visible (frame);
if (STRINGP (m) && XSTRING (m)->size)
{
set_message (NULL, m, nbytes, multibyte);
if (minibuffer_auto_raise)
Fraise_frame (frame);
}
else
clear_message (1, 1);
do_pending_window_change (0);
echo_area_display (1);
do_pending_window_change (0);
if (frame_up_to_date_hook != 0 && ! gc_in_progress)
(*frame_up_to_date_hook) (f);
}
}
void
message1 (m)
char *m;
{
message2 (m, (m ? strlen (m) : 0), 0);
}
void
message1_nolog (m)
char *m;
{
message2_nolog (m, (m ? strlen (m) : 0), 0);
}
void
message_with_string (m, string, log)
char *m;
Lisp_Object string;
int log;
{
if (noninteractive)
{
if (m)
{
if (noninteractive_need_newline)
putc ('\n', stderr);
noninteractive_need_newline = 0;
fprintf (stderr, m, XSTRING (string)->data);
if (cursor_in_echo_area == 0)
fprintf (stderr, "\n");
fflush (stderr);
}
}
else if (INTERACTIVE)
{
Lisp_Object mini_window;
struct frame *f, *sf = SELECTED_FRAME ();
mini_window = FRAME_MINIBUF_WINDOW (sf);
f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
if (FRAME_MESSAGE_BUF (f))
{
int len;
char *a[1];
a[0] = (char *) XSTRING (string)->data;
len = doprnt (FRAME_MESSAGE_BUF (f),
FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, 3, a);
if (log)
message2 (FRAME_MESSAGE_BUF (f), len,
STRING_MULTIBYTE (string));
else
message2_nolog (FRAME_MESSAGE_BUF (f), len,
STRING_MULTIBYTE (string));
message_buf_print = 0;
}
}
}
void
message (m, a1, a2, a3)
char *m;
EMACS_INT a1, a2, a3;
{
if (noninteractive)
{
if (m)
{
if (noninteractive_need_newline)
putc ('\n', stderr);
noninteractive_need_newline = 0;
fprintf (stderr, m, a1, a2, a3);
if (cursor_in_echo_area == 0)
fprintf (stderr, "\n");
fflush (stderr);
}
}
else if (INTERACTIVE)
{
Lisp_Object mini_window;
struct frame *f, *sf = SELECTED_FRAME ();
mini_window = FRAME_MINIBUF_WINDOW (sf);
f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
if (FRAME_MESSAGE_BUF (f))
{
if (m)
{
int len;
#ifdef NO_ARG_ARRAY
char *a[3];
a[0] = (char *) a1;
a[1] = (char *) a2;
a[2] = (char *) a3;
len = doprnt (FRAME_MESSAGE_BUF (f),
FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, 3, a);
#else
len = doprnt (FRAME_MESSAGE_BUF (f),
FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, 3,
(char **) &a1);
#endif
message2 (FRAME_MESSAGE_BUF (f), len, 0);
}
else
message1 (0);
message_buf_print = 0;
}
}
}
void
message_nolog (m, a1, a2, a3)
char *m;
EMACS_INT a1, a2, a3;
{
Lisp_Object old_log_max;
old_log_max = Vmessage_log_max;
Vmessage_log_max = Qnil;
message (m, a1, a2, a3);
Vmessage_log_max = old_log_max;
}
void
update_echo_area ()
{
if (!NILP (echo_area_buffer[0]))
{
Lisp_Object string;
string = Fcurrent_message ();
message3 (string, XSTRING (string)->size,
!NILP (current_buffer->enable_multibyte_characters));
}
}
static void
ensure_echo_area_buffers ()
{
int i;
for (i = 0; i < 2; ++i)
if (!BUFFERP (echo_buffer[i])
|| NILP (XBUFFER (echo_buffer[i])->name))
{
char name[30];
Lisp_Object old_buffer;
int j;
old_buffer = echo_buffer[i];
sprintf (name, " *Echo Area %d*", i);
echo_buffer[i] = Fget_buffer_create (build_string (name));
XBUFFER (echo_buffer[i])->truncate_lines = Qnil;
for (j = 0; j < 2; ++j)
if (EQ (old_buffer, echo_area_buffer[j]))
echo_area_buffer[j] = echo_buffer[i];
}
}
static int
with_echo_area_buffer (w, which, fn, a1, a2, a3, a4)
struct window *w;
int which;
int (*fn) P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
EMACS_INT a1;
Lisp_Object a2;
EMACS_INT a3, a4;
{
Lisp_Object buffer;
int this_one, the_other, clear_buffer_p, rc;
int count = BINDING_STACK_SIZE ();
ensure_echo_area_buffers ();
clear_buffer_p = 0;
if (which == 0)
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;
if (!NILP (echo_area_buffer[this_one])
&& EQ (echo_area_buffer[this_one], echo_area_buffer[the_other]))
echo_area_buffer[this_one] = Qnil;
}
if (NILP (echo_area_buffer[this_one]))
{
echo_area_buffer[this_one]
= (EQ (echo_area_buffer[the_other], echo_buffer[this_one])
? echo_buffer[the_other]
: echo_buffer[this_one]);
clear_buffer_p = 1;
}
buffer = echo_area_buffer[this_one];
if (echo_kboard == NULL && EQ (buffer, echo_message_buffer))
cancel_echoing ();
record_unwind_protect (unwind_with_echo_area_buffer,
with_echo_area_buffer_unwind_data (w));
set_buffer_internal_1 (XBUFFER (buffer));
if (w)
{
w->buffer = buffer;
set_marker_both (w->pointm, buffer, BEG, BEG_BYTE);
}
current_buffer->undo_list = Qt;
current_buffer->read_only = Qnil;
specbind (Qinhibit_read_only, Qt);
specbind (Qinhibit_modification_hooks, Qt);
if (clear_buffer_p && Z > BEG)
del_range (BEG, Z);
xassert (BEGV >= BEG);
xassert (ZV <= Z && ZV >= BEGV);
rc = fn (a1, a2, a3, a4);
xassert (BEGV >= BEG);
xassert (ZV <= Z && ZV >= BEGV);
unbind_to (count, Qnil);
return rc;
}
static Lisp_Object
with_echo_area_buffer_unwind_data (w)
struct window *w;
{
int i = 0;
Lisp_Object vector;
vector = Vwith_echo_area_save_vector;
Vwith_echo_area_save_vector = Qnil;
if (NILP (vector))
vector = Fmake_vector (make_number (7), Qnil);
XSETBUFFER (AREF (vector, i), current_buffer); ++i;
AREF (vector, i) = Vdeactivate_mark, ++i;
AREF (vector, i) = make_number (windows_or_buffers_changed), ++i;
if (w)
{
XSETWINDOW (AREF (vector, i), w); ++i;
AREF (vector, i) = w->buffer; ++i;
AREF (vector, i) = make_number (XMARKER (w->pointm)->charpos); ++i;
AREF (vector, i) = make_number (XMARKER (w->pointm)->bytepos); ++i;
}
else
{
int end = i + 4;
for (; i < end; ++i)
AREF (vector, i) = Qnil;
}
xassert (i == ASIZE (vector));
return vector;
}
static Lisp_Object
unwind_with_echo_area_buffer (vector)
Lisp_Object vector;
{
set_buffer_internal_1 (XBUFFER (AREF (vector, 0)));
Vdeactivate_mark = AREF (vector, 1);
windows_or_buffers_changed = XFASTINT (AREF (vector, 2));
if (WINDOWP (AREF (vector, 3)))
{
struct window *w;
Lisp_Object buffer, charpos, bytepos;
w = XWINDOW (AREF (vector, 3));
buffer = AREF (vector, 4);
charpos = AREF (vector, 5);
bytepos = AREF (vector, 6);
w->buffer = buffer;
set_marker_both (w->pointm, buffer,
XFASTINT (charpos), XFASTINT (bytepos));
}
Vwith_echo_area_save_vector = vector;
return Qnil;
}
void
setup_echo_area_for_printing (multibyte_p)
int multibyte_p;
{
ensure_echo_area_buffers ();
if (!message_buf_print)
{
if (EQ (echo_area_buffer[1], echo_buffer[0]))
echo_area_buffer[0] = echo_buffer[1];
else
echo_area_buffer[0] = echo_buffer[0];
set_buffer_internal (XBUFFER (echo_area_buffer[0]));
current_buffer->truncate_lines = Qnil;
if (Z > BEG)
{
int count = BINDING_STACK_SIZE ();
specbind (Qinhibit_read_only, Qt);
del_range (BEG, Z);
unbind_to (count, Qnil);
}
TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
if (multibyte_p
!= !NILP (current_buffer->enable_multibyte_characters))
Fset_buffer_multibyte (multibyte_p ? Qt : Qnil);
if (minibuffer_auto_raise)
{
struct frame *sf = SELECTED_FRAME ();
Lisp_Object mini_window;
mini_window = FRAME_MINIBUF_WINDOW (sf);
Fraise_frame (WINDOW_FRAME (XWINDOW (mini_window)));
}
message_log_maybe_newline ();
message_buf_print = 1;
}
else
{
if (NILP (echo_area_buffer[0]))
{
if (EQ (echo_area_buffer[1], echo_buffer[0]))
echo_area_buffer[0] = echo_buffer[1];
else
echo_area_buffer[0] = echo_buffer[0];
}
if (current_buffer != XBUFFER (echo_area_buffer[0]))
{
set_buffer_internal (XBUFFER (echo_area_buffer[0]));
current_buffer->truncate_lines = Qnil;
}
}
}
static int
display_echo_area (w)
struct window *w;
{
int i, no_message_p, window_height_changed_p, count;
count = inhibit_garbage_collection ();
i = display_last_displayed_message_p ? 1 : 0;
no_message_p = NILP (echo_area_buffer[i]);
window_height_changed_p
= with_echo_area_buffer (w, display_last_displayed_message_p,
display_echo_area_1,
(EMACS_INT) w, Qnil, 0, 0);
if (no_message_p)
echo_area_buffer[i] = Qnil;
unbind_to (count, Qnil);
return window_height_changed_p;
}
static int
display_echo_area_1 (a1, a2, a3, a4)
EMACS_INT a1;
Lisp_Object a2;
EMACS_INT a3, a4;
{
struct window *w = (struct window *) a1;
Lisp_Object window;
struct text_pos start;
int window_height_changed_p = 0;
window_height_changed_p = resize_mini_window (w, 0);
clear_glyph_matrix (w->desired_matrix);
XSETWINDOW (window, w);
SET_TEXT_POS (start, BEG, BEG_BYTE);
try_window (window, start);
return window_height_changed_p;
}
void
resize_echo_area_exactly ()
{
if (BUFFERP (echo_area_buffer[0])
&& WINDOWP (echo_area_window))
{
struct window *w = XWINDOW (echo_area_window);
int resized_p;
Lisp_Object resize_exactly;
if (minibuf_level == 0)
resize_exactly = Qt;
else
resize_exactly = Qnil;
resized_p = with_echo_area_buffer (w, 0, resize_mini_window_1,
(EMACS_INT) w, resize_exactly, 0, 0);
if (resized_p)
{
++windows_or_buffers_changed;
++update_mode_lines;
redisplay_internal (0);
}
}
}
static int
resize_mini_window_1 (a1, exactly, a3, a4)
EMACS_INT a1;
Lisp_Object exactly;
EMACS_INT a3, a4;
{
return resize_mini_window ((struct window *) a1, !NILP (exactly));
}
int
resize_mini_window (w, exact_p)
struct window *w;
int exact_p;
{
struct frame *f = XFRAME (w->frame);
int window_height_changed_p = 0;
xassert (MINI_WINDOW_P (w));
if (!NILP (Vinhibit_redisplay))
return 0;
if (NILP (Vresize_mini_windows)
|| (FRAME_X_P (f) && f->output_data.x == NULL))
return 0;
if (!FRAME_MINIBUF_ONLY_P (f))
{
struct it it;
struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
int total_height = XFASTINT (root->height) + XFASTINT (w->height);
int height, max_height;
int unit = CANON_Y_UNIT (f);
struct text_pos start;
struct buffer *old_current_buffer = NULL;
if (current_buffer != XBUFFER (w->buffer))
{
old_current_buffer = current_buffer;
set_buffer_internal (XBUFFER (w->buffer));
}
init_iterator (&it, w, BEGV, BEGV_BYTE, NULL, DEFAULT_FACE_ID);
if (FLOATP (Vmax_mini_window_height))
max_height = XFLOATINT (Vmax_mini_window_height) * FRAME_HEIGHT (f);
else if (INTEGERP (Vmax_mini_window_height))
max_height = XINT (Vmax_mini_window_height);
else
max_height = total_height / 4;
max_height = max (1, max_height);
max_height = min (total_height, max_height);
if (it.truncate_lines_p)
height = 1;
else
{
last_height = 0;
move_it_to (&it, ZV, -1, -1, -1, MOVE_TO_POS);
if (it.max_ascent == 0 && it.max_descent == 0)
height = it.current_y + last_height;
else
height = it.current_y + it.max_ascent + it.max_descent;
height -= it.extra_line_spacing;
height = (height + unit - 1) / unit;
}
if (height > max_height)
{
height = max_height;
init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
move_it_vertically_backward (&it, (height - 1) * unit);
start = it.current.pos;
}
else
SET_TEXT_POS (start, BEGV, BEGV_BYTE);
SET_MARKER_FROM_TEXT_POS (w->start, start);
if (EQ (Vresize_mini_windows, Qgrow_only))
{
if (height > XFASTINT (w->height))
{
int old_height = XFASTINT (w->height);
freeze_window_starts (f, 1);
grow_mini_window (w, height - XFASTINT (w->height));
window_height_changed_p = XFASTINT (w->height) != old_height;
}
else if (height < XFASTINT (w->height)
&& (exact_p || BEGV == ZV))
{
int old_height = XFASTINT (w->height);
freeze_window_starts (f, 0);
shrink_mini_window (w);
window_height_changed_p = XFASTINT (w->height) != old_height;
}
}
else
{
if (height > XFASTINT (w->height))
{
int old_height = XFASTINT (w->height);
freeze_window_starts (f, 1);
grow_mini_window (w, height - XFASTINT (w->height));
window_height_changed_p = XFASTINT (w->height) != old_height;
}
else if (height < XFASTINT (w->height))
{
int old_height = XFASTINT (w->height);
freeze_window_starts (f, 0);
shrink_mini_window (w);
if (height)
{
freeze_window_starts (f, 1);
grow_mini_window (w, height - XFASTINT (w->height));
}
window_height_changed_p = XFASTINT (w->height) != old_height;
}
}
if (old_current_buffer)
set_buffer_internal (old_current_buffer);
}
return window_height_changed_p;
}
Lisp_Object
current_message ()
{
Lisp_Object msg;
if (NILP (echo_area_buffer[0]))
msg = Qnil;
else
{
with_echo_area_buffer (0, 0, current_message_1,
(EMACS_INT) &msg, Qnil, 0, 0);
if (NILP (msg))
echo_area_buffer[0] = Qnil;
}
return msg;
}
static int
current_message_1 (a1, a2, a3, a4)
EMACS_INT a1;
Lisp_Object a2;
EMACS_INT a3, a4;
{
Lisp_Object *msg = (Lisp_Object *) a1;
if (Z > BEG)
*msg = make_buffer_string (BEG, Z, 1);
else
*msg = Qnil;
return 0;
}
int
push_message ()
{
Lisp_Object msg;
msg = current_message ();
Vmessage_stack = Fcons (msg, Vmessage_stack);
return STRINGP (msg);
}
Lisp_Object
push_message_unwind (dummy)
Lisp_Object dummy;
{
pop_message ();
return Qnil;
}
void
restore_message ()
{
Lisp_Object msg;
xassert (CONSP (Vmessage_stack));
msg = XCAR (Vmessage_stack);
if (STRINGP (msg))
message3_nolog (msg, STRING_BYTES (XSTRING (msg)), STRING_MULTIBYTE (msg));
else
message3_nolog (msg, 0, 0);
}
void
pop_message ()
{
xassert (CONSP (Vmessage_stack));
Vmessage_stack = XCDR (Vmessage_stack);
}
void
check_message_stack ()
{
if (!NILP (Vmessage_stack))
abort ();
}
void
truncate_echo_area (nchars)
int nchars;
{
if (nchars == 0)
echo_area_buffer[0] = Qnil;
else if (!noninteractive
&& INTERACTIVE
&& !NILP (echo_area_buffer[0]))
{
struct frame *sf = SELECTED_FRAME ();
if (FRAME_MESSAGE_BUF (sf))
with_echo_area_buffer (0, 0, truncate_message_1, nchars, Qnil, 0, 0);
}
}
static int
truncate_message_1 (nchars, a2, a3, a4)
EMACS_INT nchars;
Lisp_Object a2;
EMACS_INT a3, a4;
{
if (BEG + nchars < Z)
del_range (BEG + nchars, Z);
if (Z == BEG)
echo_area_buffer[0] = Qnil;
return 0;
}
void
set_message (s, string, nbytes, multibyte_p)
char *s;
Lisp_Object string;
int nbytes;
{
message_enable_multibyte
= ((s && multibyte_p)
|| (STRINGP (string) && STRING_MULTIBYTE (string)));
with_echo_area_buffer (0, -1, set_message_1,
(EMACS_INT) s, string, nbytes, multibyte_p);
message_buf_print = 0;
help_echo_showing_p = 0;
}
static int
set_message_1 (a1, a2, nbytes, multibyte_p)
EMACS_INT a1;
Lisp_Object a2;
EMACS_INT nbytes, multibyte_p;
{
char *s = (char *) a1;
Lisp_Object string = a2;
xassert (BEG == Z);
if (message_enable_multibyte
!= !NILP (current_buffer->enable_multibyte_characters))
Fset_buffer_multibyte (message_enable_multibyte ? Qt : Qnil);
current_buffer->truncate_lines = message_truncate_lines ? Qt : Qnil;
TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
if (STRINGP (string))
{
int nchars;
if (nbytes == 0)
nbytes = XSTRING (string)->size_byte;
nchars = string_byte_to_char (string, nbytes);
insert_from_string (string, 0, 0, nchars, nbytes, 1);
}
else if (s)
{
if (nbytes == 0)
nbytes = strlen (s);
if (multibyte_p && NILP (current_buffer->enable_multibyte_characters))
{
int i, c, n;
unsigned char work[1];
for (i = 0; i < nbytes; i += n)
{
c = string_char_and_length (s + i, nbytes - i, &n);
work[0] = (SINGLE_BYTE_CHAR_P (c)
? c
: multibyte_char_to_unibyte (c, Qnil));
insert_1_both (work, 1, 1, 1, 0, 0);
}
}
else if (!multibyte_p
&& !NILP (current_buffer->enable_multibyte_characters))
{
int i, c, n;
unsigned char *msg = (unsigned char *) s;
unsigned char str[MAX_MULTIBYTE_LENGTH];
for (i = 0; i < nbytes; i++)
{
c = unibyte_char_to_multibyte (msg[i]);
n = CHAR_STRING (c, str);
insert_1_both (str, 1, n, 1, 0, 0);
}
}
else
insert_1 (s, nbytes, 1, 0, 0);
}
return 0;
}
void
clear_message (current_p, last_displayed_p)
int current_p, last_displayed_p;
{
if (current_p)
{
echo_area_buffer[0] = Qnil;
message_cleared_p = 1;
}
if (last_displayed_p)
echo_area_buffer[1] = Qnil;
message_buf_print = 0;
}
static void
clear_garbaged_frames ()
{
if (frame_garbaged)
{
Lisp_Object tail, frame;
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f))
{
if (f->resized_p)
Fredraw_frame (frame);
clear_current_matrices (f);
f->garbaged = f->resized_p = 0;
}
}
frame_garbaged = 0;
++windows_or_buffers_changed;
}
}
static int
echo_area_display (update_frame_p)
int update_frame_p;
{
Lisp_Object mini_window;
struct window *w;
struct frame *f;
int window_height_changed_p = 0;
struct frame *sf = SELECTED_FRAME ();
mini_window = FRAME_MINIBUF_WINDOW (sf);
w = XWINDOW (mini_window);
f = XFRAME (WINDOW_FRAME (w));
if (!FRAME_VISIBLE_P (f) || !f->glyphs_initialized_p)
return 0;
#ifndef macintosh
#ifdef HAVE_WINDOW_SYSTEM
if (EQ (selected_frame, Vterminal_frame)
&& !NILP (Vwindow_system))
return 0;
#endif
#endif
if (frame_garbaged)
clear_garbaged_frames ();
if (!NILP (echo_area_buffer[0]) || minibuf_level == 0)
{
echo_area_window = mini_window;
window_height_changed_p = display_echo_area (w);
w->must_be_updated_p = 1;
if (update_frame_p && !redisplaying_p)
{
int n = 0;
if (!display_completed)
n = redisplay_mode_lines (FRAME_ROOT_WINDOW (f), 0);
if (window_height_changed_p
&& !NILP (Vrun_hooks))
{
int count = BINDING_STACK_SIZE ();
specbind (Qredisplay_dont_pause, Qt);
windows_or_buffers_changed = 1;
redisplay_internal (0);
unbind_to (count, Qnil);
}
else if (FRAME_WINDOW_P (f) && n == 0)
{
update_single_window (w, 1);
rif->flush_display (f);
}
else
update_frame (f, 1, 1);
if (cursor_in_echo_area)
++windows_or_buffers_changed;
}
}
else if (!EQ (mini_window, selected_window))
windows_or_buffers_changed++;
echo_area_buffer[1] = echo_area_buffer[0];
if (EQ (mini_window, selected_window))
CHARPOS (this_line_start_pos) = 0;
return window_height_changed_p;
}
#ifdef HAVE_WINDOW_SYSTEM
static char *frame_title_buf;
static char *frame_title_buf_end;
static char *frame_title_ptr;
static void
store_frame_title_char (c)
char c;
{
if (frame_title_ptr == frame_title_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;
}
*frame_title_ptr++ = c;
}
static int
store_frame_title (str, field_width, precision)
unsigned char *str;
int field_width, precision;
{
int n = 0;
int dummy, nbytes, width;
nbytes = strlen (str);
n+= c_string_width (str, nbytes, precision, &dummy, &nbytes);
while (nbytes--)
store_frame_title_char (*str++);
while (field_width > 0
&& n < field_width)
{
store_frame_title_char (' ');
++n;
}
return n;
}
static void
x_consider_frame_title (frame)
Lisp_Object frame;
{
struct frame *f = XFRAME (frame);
if (FRAME_WINDOW_P (f)
|| FRAME_MINIBUF_ONLY_P (f)
|| f->explicit_name)
{
Lisp_Object tail;
Lisp_Object fmt;
struct buffer *obuf;
int len;
struct it it;
for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
{
struct frame *tf = XFRAME (XCAR (tail));
if (tf != f
&& FRAME_KBOARD (tf) == FRAME_KBOARD (f)
&& !FRAME_MINIBUF_ONLY_P (tf)
&& (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf)))
break;
}
multiple_frames = CONSP (tail);
obuf = current_buffer;
Fset_buffer (XWINDOW (f->selected_window)->buffer);
fmt = FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format;
frame_title_ptr = frame_title_buf;
init_iterator (&it, XWINDOW (f->selected_window), -1, -1,
NULL, DEFAULT_FACE_ID);
display_mode_element (&it, 0, -1, -1, fmt);
len = frame_title_ptr - frame_title_buf;
frame_title_ptr = NULL;
set_buffer_internal (obuf);
if (! STRINGP (f->name)
|| STRING_BYTES (XSTRING (f->name)) != len
|| bcmp (frame_title_buf, XSTRING (f->name)->data, len) != 0)
x_implicitly_set_name (f, make_string (frame_title_buf, len), Qnil);
}
}
#else
#define frame_title_ptr ((char *)0)
#define store_frame_title(str, mincol, maxcol) 0
#endif
void
prepare_menu_bars ()
{
int all_windows;
struct gcpro gcpro1, gcpro2;
struct frame *f;
Lisp_Object tooltip_frame;
#ifdef HAVE_X_WINDOWS
tooltip_frame = tip_frame;
#else
tooltip_frame = Qnil;
#endif
#ifdef HAVE_WINDOW_SYSTEM
if (windows_or_buffers_changed || update_mode_lines)
{
Lisp_Object tail, frame;
FOR_EACH_FRAME (tail, frame)
{
f = XFRAME (frame);
if (!EQ (frame, tooltip_frame)
&& (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f)))
x_consider_frame_title (frame);
}
}
#endif
all_windows = (update_mode_lines
|| buffer_shared > 1
|| windows_or_buffers_changed);
if (all_windows)
{
Lisp_Object tail, frame;
int count = BINDING_STACK_SIZE ();
record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
FOR_EACH_FRAME (tail, frame)
{
f = XFRAME (frame);
if (EQ (frame, tooltip_frame))
continue;
if (FRAME_WINDOW_SIZES_CHANGED (f))
{
Lisp_Object functions;
FRAME_WINDOW_SIZES_CHANGED (f) = 0;
functions = Vwindow_size_change_functions;
GCPRO2 (tail, functions);
while (CONSP (functions))
{
call1 (XCAR (functions), frame);
functions = XCDR (functions);
}
UNGCPRO;
}
GCPRO1 (tail);
update_menu_bar (f, 0);
#ifdef HAVE_WINDOW_SYSTEM
update_tool_bar (f, 0);
#endif
UNGCPRO;
}
unbind_to (count, Qnil);
}
else
{
struct frame *sf = SELECTED_FRAME ();
update_menu_bar (sf, 1);
#ifdef HAVE_WINDOW_SYSTEM
update_tool_bar (sf, 1);
#endif
}
#ifdef USE_X_TOOLKIT
pending_menu_activation = 0;
#endif
}
static void
update_menu_bar (f, save_match_data)
struct frame *f;
int save_match_data;
{
Lisp_Object window;
register struct window *w;
if (inhibit_menubar_update)
return;
window = FRAME_SELECTED_WINDOW (f);
w = XWINDOW (window);
if (update_mode_lines)
w->update_mode_line = Qt;
if (FRAME_WINDOW_P (f)
?
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
FRAME_EXTERNAL_MENU_BAR (f)
#else
FRAME_MENU_BAR_LINES (f) > 0
#endif
: FRAME_MENU_BAR_LINES (f) > 0)
{
if (windows_or_buffers_changed
|| !NILP (w->update_mode_line)
|| ((BUF_SAVE_MODIFF (XBUFFER (w->buffer))
< BUF_MODIFF (XBUFFER (w->buffer)))
!= !NILP (w->last_had_star))
|| ((!NILP (Vtransient_mark_mode)
&& !NILP (XBUFFER (w->buffer)->mark_active))
!= !NILP (w->region_showing)))
{
struct buffer *prev = current_buffer;
int count = BINDING_STACK_SIZE ();
specbind (Qinhibit_menubar_update, Qt);
set_buffer_internal_1 (XBUFFER (w->buffer));
if (save_match_data)
record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
if (NILP (Voverriding_local_map_menu_flag))
{
specbind (Qoverriding_terminal_local_map, Qnil);
specbind (Qoverriding_local_map, Qnil);
}
safe_run_hooks (Qactivate_menubar_hook);
if (! NILP (Vlucid_menu_bar_dirty_flag))
call0 (Qrecompute_lucid_menubar);
safe_run_hooks (Qmenu_bar_update_hook);
FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
if (FRAME_WINDOW_P (f)
#if defined (macintosh)
&& f == SELECTED_FRAME ()
#endif
)
set_frame_menubar (f, 0, 0);
else
w->update_mode_line = Qt;
#else
w->update_mode_line = Qt;
#endif
unbind_to (count, Qnil);
set_buffer_internal_1 (prev);
}
}
}
#ifdef HAVE_WINDOW_SYSTEM
static void
update_tool_bar (f, save_match_data)
struct frame *f;
int save_match_data;
{
if (WINDOWP (f->tool_bar_window)
&& XFASTINT (XWINDOW (f->tool_bar_window)->height) > 0)
{
Lisp_Object window;
struct window *w;
window = FRAME_SELECTED_WINDOW (f);
w = XWINDOW (window);
if (windows_or_buffers_changed
|| !NILP (w->update_mode_line)
|| ((BUF_SAVE_MODIFF (XBUFFER (w->buffer))
< BUF_MODIFF (XBUFFER (w->buffer)))
!= !NILP (w->last_had_star))
|| ((!NILP (Vtransient_mark_mode)
&& !NILP (XBUFFER (w->buffer)->mark_active))
!= !NILP (w->region_showing)))
{
struct buffer *prev = current_buffer;
int count = BINDING_STACK_SIZE ();
set_buffer_internal_1 (XBUFFER (w->buffer));
if (save_match_data)
record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
if (NILP (Voverriding_local_map_menu_flag))
{
specbind (Qoverriding_terminal_local_map, Qnil);
specbind (Qoverriding_local_map, Qnil);
}
f->tool_bar_items
= tool_bar_items (f->tool_bar_items, &f->n_tool_bar_items);
w->update_mode_line = Qt;
unbind_to (count, Qnil);
set_buffer_internal_1 (prev);
}
}
}
static void
build_desired_tool_bar_string (f)
struct frame *f;
{
int i, size, size_needed;
struct gcpro gcpro1, gcpro2, gcpro3;
Lisp_Object image, plist, props;
image = plist = props = Qnil;
GCPRO3 (image, plist, props);
size = (STRINGP (f->desired_tool_bar_string)
? XSTRING (f->desired_tool_bar_string)->size
: 0);
size_needed = f->n_tool_bar_items;
if (size < size_needed || NILP (f->desired_tool_bar_string))
f->desired_tool_bar_string = Fmake_string (make_number (size_needed),
make_number (' '));
else
{
props = list4 (Qdisplay, Qnil, Qmenu_item, Qnil);
Fremove_text_properties (make_number (0), make_number (size),
props, f->desired_tool_bar_string);
}
for (i = 0; i < f->n_tool_bar_items; ++i)
{
#define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
int hmargin, vmargin, relief, idx, end;
extern Lisp_Object QCrelief, QCmargin, QCconversion, Qimage;
extern Lisp_Object Qlaplace;
image = PROP (TOOL_BAR_ITEM_IMAGES);
if (VECTORP (image))
{
if (enabled_p)
idx = (selected_p
? TOOL_BAR_IMAGE_ENABLED_SELECTED
: TOOL_BAR_IMAGE_ENABLED_DESELECTED);
else
idx = (selected_p
? TOOL_BAR_IMAGE_DISABLED_SELECTED
: TOOL_BAR_IMAGE_DISABLED_DESELECTED);
xassert (ASIZE (image) >= idx);
image = AREF (image, idx);
}
else
idx = -1;
if (!valid_image_p (image))
continue;
plist = Fcopy_sequence (XCDR (image));
relief = (tool_bar_button_relief > 0
? tool_bar_button_relief
: DEFAULT_TOOL_BAR_BUTTON_RELIEF);
hmargin = vmargin = relief;
if (INTEGERP (Vtool_bar_button_margin)
&& XINT (Vtool_bar_button_margin) > 0)
{
hmargin += XFASTINT (Vtool_bar_button_margin);
vmargin += XFASTINT (Vtool_bar_button_margin);
}
else if (CONSP (Vtool_bar_button_margin))
{
if (INTEGERP (XCAR (Vtool_bar_button_margin))
&& XINT (XCAR (Vtool_bar_button_margin)) > 0)
hmargin += XFASTINT (XCAR (Vtool_bar_button_margin));
if (INTEGERP (XCDR (Vtool_bar_button_margin))
&& XINT (XCDR (Vtool_bar_button_margin)) > 0)
vmargin += XFASTINT (XCDR (Vtool_bar_button_margin));
}
if (auto_raise_tool_bar_buttons_p)
{
if (selected_p)
{
plist = Fplist_put (plist, QCrelief, make_number (-relief));
hmargin -= relief;
vmargin -= relief;
}
}
else
{
plist = Fplist_put (plist, QCrelief,
(selected_p
? make_number (-relief)
: make_number (relief)));
hmargin -= relief;
vmargin -= relief;
}
if (hmargin || vmargin)
{
if (hmargin == vmargin)
plist = Fplist_put (plist, QCmargin, make_number (hmargin));
else
plist = Fplist_put (plist, QCmargin,
Fcons (make_number (hmargin),
make_number (vmargin)));
}
if (!enabled_p && idx < 0)
plist = Fplist_put (plist, QCconversion, Qdisabled);
image = Fcons (Qimage, plist);
props = list4 (Qdisplay, image,
Qmenu_item, make_number (i * TOOL_BAR_ITEM_NSLOTS));
if (i + 1 == f->n_tool_bar_items)
end = XSTRING (f->desired_tool_bar_string)->size;
else
end = i + 1;
Fadd_text_properties (make_number (i), make_number (end),
props, f->desired_tool_bar_string);
#undef PROP
}
UNGCPRO;
}
static void
display_tool_bar_line (it)
struct it *it;
{
struct glyph_row *row = it->glyph_row;
int max_x = it->last_visible_x;
struct glyph *last;
prepare_desired_row (row);
row->y = it->current_y;
it->start_of_box_run_p = 1;
while (it->current_x < max_x)
{
int x_before, x, n_glyphs_before, i, nglyphs;
if (!get_next_display_element (it))
break;
x_before = it->current_x;
n_glyphs_before = it->glyph_row->used[TEXT_AREA];
PRODUCE_GLYPHS (it);
nglyphs = it->glyph_row->used[TEXT_AREA] - n_glyphs_before;
i = 0;
x = x_before;
while (i < nglyphs)
{
struct glyph *glyph = row->glyphs[TEXT_AREA] + n_glyphs_before + i;
if (x + glyph->pixel_width > max_x)
{
it->glyph_row->used[TEXT_AREA] = n_glyphs_before + i;
it->current_x = x;
goto out;
}
++it->hpos;
x += glyph->pixel_width;
++i;
}
if (ITERATOR_AT_END_OF_LINE_P (it))
break;
set_iterator_to_next (it, 1);
}
out:;
row->displays_text_p = row->used[TEXT_AREA] != 0;
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;
compute_line_metrics (it);
if (!row->displays_text_p)
{
row->height = row->phys_height = it->last_visible_y - row->y;
row->ascent = row->phys_ascent = 0;
}
row->full_width_p = 1;
row->continued_p = 0;
row->truncated_on_left_p = 0;
row->truncated_on_right_p = 0;
it->current_x = it->hpos = 0;
it->current_y += row->height;
++it->vpos;
++it->glyph_row;
}
static int
tool_bar_lines_needed (f)
struct frame *f;
{
struct window *w = XWINDOW (f->tool_bar_window);
struct it it;
init_iterator (&it, w, -1, -1, w->desired_matrix->rows, TOOL_BAR_FACE_ID);
it.first_visible_x = 0;
it.last_visible_x = FRAME_WINDOW_WIDTH (f) * CANON_X_UNIT (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);
}
return (it.current_y + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
}
DEFUN ("tool-bar-lines-needed", Ftool_bar_lines_needed, Stool_bar_lines_needed,
0, 1, 0,
"Return the number of lines occupied by the tool bar of FRAME.")
(frame)
Lisp_Object frame;
{
struct frame *f;
struct window *w;
int nlines = 0;
if (NILP (frame))
frame = selected_frame;
else
CHECK_FRAME (frame, 0);
f = XFRAME (frame);
if (WINDOWP (f->tool_bar_window)
|| (w = XWINDOW (f->tool_bar_window),
XFASTINT (w->height) > 0))
{
update_tool_bar (f, 1);
if (f->n_tool_bar_items)
{
build_desired_tool_bar_string (f);
nlines = tool_bar_lines_needed (f);
}
}
return make_number (nlines);
}
static int
redisplay_tool_bar (f)
struct frame *f;
{
struct window *w;
struct it it;
struct glyph_row *row;
int change_height_p = 0;
if (!WINDOWP (f->tool_bar_window)
|| (w = XWINDOW (f->tool_bar_window),
XFASTINT (w->height) == 0))
return 0;
init_iterator (&it, w, -1, -1, w->desired_matrix->rows, TOOL_BAR_FACE_ID);
it.first_visible_x = 0;
it.last_visible_x = FRAME_WINDOW_WIDTH (f) * CANON_X_UNIT (f);
row = it.glyph_row;
build_desired_tool_bar_string (f);
reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
while (it.current_y < it.last_visible_y)
display_tool_bar_line (&it);
w->desired_matrix->no_scrolling_p = 1;
w->must_be_updated_p = 1;
if (auto_resize_tool_bars_p)
{
int nlines;
if (IT_STRING_CHARPOS (it) < it.end_charpos)
change_height_p = 1;
row = it.glyph_row - 1;
if (!row->displays_text_p
&& row->height >= CANON_Y_UNIT (f))
change_height_p = 1;
if (row->displays_text_p
&& MATRIX_ROW_BOTTOM_Y (row) > it.last_visible_y)
change_height_p = 1;
if (change_height_p
&& (nlines = tool_bar_lines_needed (f),
nlines != XFASTINT (w->height)))
{
extern Lisp_Object Qtool_bar_lines;
Lisp_Object frame;
int old_height = XFASTINT (w->height);
XSETFRAME (frame, f);
clear_glyph_matrix (w->desired_matrix);
Fmodify_frame_parameters (frame,
Fcons (Fcons (Qtool_bar_lines,
make_number (nlines)),
Qnil));
if (XFASTINT (w->height) != old_height)
fonts_changed_p = 1;
}
}
return change_height_p;
}
int
tool_bar_item_info (f, glyph, prop_idx)
struct frame *f;
struct glyph *glyph;
int *prop_idx;
{
Lisp_Object prop;
int success_p;
int charpos;
charpos = min (XSTRING (f->current_tool_bar_string)->size, glyph->charpos);
charpos = max (0, charpos);
prop = Fget_text_property (make_number (charpos),
Qmenu_item, f->current_tool_bar_string);
if (INTEGERP (prop))
{
*prop_idx = XINT (prop);
success_p = 1;
}
else
success_p = 0;
return success_p;
}
#endif
static int hscroll_window_tree P_ ((Lisp_Object));
static int hscroll_windows P_ ((Lisp_Object));
static int
hscroll_window_tree (window)
Lisp_Object window;
{
int hscrolled_p = 0;
while (WINDOWP (window))
{
struct window *w = XWINDOW (window);
if (WINDOWP (w->hchild))
hscrolled_p |= hscroll_window_tree (w->hchild);
else if (WINDOWP (w->vchild))
hscrolled_p |= hscroll_window_tree (w->vchild);
else if (w->cursor.vpos >= 0)
{
int hscroll_margin, text_area_x, text_area_y;
int text_area_width, text_area_height;
struct glyph_row *current_cursor_row
= MATRIX_ROW (w->current_matrix, w->cursor.vpos);
struct glyph_row *desired_cursor_row
= MATRIX_ROW (w->desired_matrix, w->cursor.vpos);
struct glyph_row *cursor_row
= (desired_cursor_row->enabled_p
? desired_cursor_row
: current_cursor_row);
window_box (w, TEXT_AREA, &text_area_x, &text_area_y,
&text_area_width, &text_area_height);
hscroll_margin = 5 * CANON_X_UNIT (XFRAME (w->frame));
if ((XFASTINT (w->hscroll)
&& w->cursor.x < hscroll_margin)
|| (cursor_row->enabled_p
&& cursor_row->truncated_on_right_p
&& (w->cursor.x > text_area_width - hscroll_margin)))
{
struct it it;
int hscroll;
struct buffer *saved_current_buffer;
int pt;
saved_current_buffer = current_buffer;
current_buffer = XBUFFER (w->buffer);
if (w == XWINDOW (selected_window))
pt = BUF_PT (current_buffer);
else
{
pt = marker_position (w->pointm);
pt = max (BEGV, pt);
pt = min (ZV, pt);
}
init_to_row_start (&it, w, cursor_row);
it.last_visible_x = INFINITY;
move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS);
current_buffer = saved_current_buffer;
hscroll = (max (0, it.current_x - text_area_width / 2)
/ CANON_X_UNIT (it.f));
hscroll = max (hscroll, XFASTINT (w->min_hscroll));
if (XFASTINT (w->hscroll) != hscroll)
{
XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
w->hscroll = make_number (hscroll);
hscrolled_p = 1;
}
}
}
window = w->next;
}
return hscrolled_p;
}
static int
hscroll_windows (window)
Lisp_Object window;
{
int hscrolled_p;
if (automatic_hscrolling_p)
{
hscrolled_p = hscroll_window_tree (window);
if (hscrolled_p)
clear_desired_matrices (XFRAME (WINDOW_FRAME (XWINDOW (window))));
}
else
hscrolled_p = 0;
return hscrolled_p;
}
#if GLYPH_DEBUG
int debug_first_unchanged_at_end_vpos;
int debug_last_unchanged_at_beg_vpos;
int debug_dvpos, debug_dy;
int debug_delta, debug_delta_bytes;
int debug_end_pos, debug_end_vpos;
static void
debug_method_add (w, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
struct window *w;
char *fmt;
int a1, a2, a3, a4, a5, a6, a7, a8, a9;
{
char buffer[512];
char *method = w->desired_matrix->method;
int len = strlen (method);
int size = sizeof w->desired_matrix->method;
int remaining = size - len - 1;
sprintf (buffer, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
if (len && remaining)
{
method[len] = '|';
--remaining, ++len;
}
strncpy (method + len, buffer, remaining);
if (trace_redisplay_p)
fprintf (stderr, "%p (%s): %s\n",
w,
((BUFFERP (w->buffer)
&& STRINGP (XBUFFER (w->buffer)->name))
? (char *) XSTRING (XBUFFER (w->buffer)->name)->data
: "no buffer"),
buffer);
}
#endif
#define CLEAR_FACE_CACHE_COUNT 10000
static int clear_face_cache_count;
static struct frame *previous_terminal_frame;
int redisplaying_p;
static INLINE int
text_outside_line_unchanged_p (w, start, end)
struct window *w;
int start, end;
{
int unchanged_p = 1;
if (XFASTINT (w->last_modified) < MODIFF
|| XFASTINT (w->last_overlay_modified) < OVERLAY_MODIFF)
{
if (GPT < start || Z - GPT < end)
unchanged_p = 0;
if (unchanged_p
&& (BEG_UNCHANGED < start - 1
|| END_UNCHANGED < end))
unchanged_p = 0;
if (unchanged_p
&& INTEGERP (current_buffer->selective_display)
&& XINT (current_buffer->selective_display) > 0
&& (BEG_UNCHANGED < start || GPT <= start))
unchanged_p = 0;
if (unchanged_p)
{
if (BEG + BEG_UNCHANGED == start
&& overlay_touches_p (start))
unchanged_p = 0;
if (END_UNCHANGED == end
&& overlay_touches_p (Z - end))
unchanged_p = 0;
}
}
return unchanged_p;
}
void
redisplay ()
{
redisplay_internal (0);
}
int
check_point_in_composition (prev_buf, prev_pt, buf, pt)
struct buffer *prev_buf, *buf;
int prev_pt, pt;
{
int start, end;
Lisp_Object prop;
Lisp_Object buffer;
XSETBUFFER (buffer, buf);
if (prev_buf == buf)
{
if (prev_pt == pt)
return 0;
if (prev_pt > BUF_BEGV (buf) && prev_pt < BUF_ZV (buf)
&& find_composition (prev_pt, -1, &start, &end, &prop, buffer)
&& COMPOSITION_VALID_P (start, end, prop)
&& start < prev_pt && end > prev_pt)
return (pt <= start || pt >= end);
}
return (pt > BUF_BEGV (buf) && pt < BUF_ZV (buf)
&& find_composition (pt, -1, &start, &end, &prop, buffer)
&& COMPOSITION_VALID_P (start, end, prop)
&& start < pt && end > pt);
}
static INLINE void
reconsider_clip_changes (w, b)
struct window *w;
struct buffer *b;
{
if (b->prevent_redisplay_optimizations_p)
b->clip_changed = 1;
else if (b->clip_changed
&& !NILP (w->window_end_valid)
&& w->current_matrix->buffer == b
&& w->current_matrix->zv == BUF_ZV (b)
&& w->current_matrix->begv == BUF_BEGV (b))
b->clip_changed = 0;
if (!b->clip_changed
&& BUFFERP (w->buffer) && !NILP (w->window_end_valid))
{
int pt;
if (w == XWINDOW (selected_window))
pt = BUF_PT (current_buffer);
else
pt = marker_position (w->pointm);
if ((w->current_matrix->buffer != XBUFFER (w->buffer)
|| pt != XINT (w->last_point))
&& check_point_in_composition (w->current_matrix->buffer,
XINT (w->last_point),
XBUFFER (w->buffer), pt))
b->clip_changed = 1;
}
}
static void
redisplay_internal (preserve_echo_area)
int preserve_echo_area;
{
struct window *w = XWINDOW (selected_window);
struct frame *f = XFRAME (w->frame);
int pause;
int must_finish = 0;
struct text_pos tlbufpos, tlendpos;
int number_of_visible_frames;
int count;
struct frame *sf = SELECTED_FRAME ();
int consider_all_windows_p;
TRACE ((stderr, "redisplay_internal %d\n", redisplaying_p));
if (noninteractive
|| !NILP (Vinhibit_redisplay)
|| !f->glyphs_initialized_p)
return;
if (redisplay_performed_directly_p)
{
redisplay_performed_directly_p = 0;
if (!hscroll_windows (selected_window))
return;
}
#ifdef USE_X_TOOLKIT
if (popup_activated ())
return;
#endif
if (redisplaying_p)
return;
count = BINDING_STACK_SIZE ();
record_unwind_protect (unwind_redisplay, make_number (redisplaying_p));
++redisplaying_p;
retry:
pause = 0;
reconsider_clip_changes (w, current_buffer);
if (fonts_changed_p)
{
adjust_glyphs (NULL);
++windows_or_buffers_changed;
fonts_changed_p = 0;
}
if (face_change_count)
++windows_or_buffers_changed;
if (! FRAME_WINDOW_P (sf)
&& previous_terminal_frame != sf)
{
windows_or_buffers_changed++;
SET_FRAME_GARBAGED (sf);
XSETFRAME (Vterminal_frame, sf);
}
previous_terminal_frame = sf;
{
Lisp_Object tail, frame;
number_of_visible_frames = 0;
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
FRAME_SAMPLE_VISIBILITY (f);
if (FRAME_VISIBLE_P (f))
++number_of_visible_frames;
clear_desired_matrices (f);
}
}
do_pending_window_change (1);
if (frame_garbaged)
clear_garbaged_frames ();
prepare_menu_bars ();
if (windows_or_buffers_changed)
update_mode_lines++;
if ((SAVE_MODIFF < MODIFF) != !NILP (w->last_had_star))
{
w->update_mode_line = Qt;
if (buffer_shared > 1)
update_mode_lines++;
}
if (!NILP (w->column_number_displayed)
&& !(PT == XFASTINT (w->last_point)
&& XFASTINT (w->last_modified) >= MODIFF
&& XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)
&& XFASTINT (w->column_number_displayed) != current_column ())
w->update_mode_line = Qt;
FRAME_SCROLL_BOTTOM_VPOS (XFRAME (w->frame)) = -1;
consider_all_windows_p = update_mode_lines || buffer_shared > 1;
if (! EQ (COERCE_MARKER (Voverlay_arrow_position), last_arrow_position)
|| ! EQ (Voverlay_arrow_string, last_arrow_string))
consider_all_windows_p = windows_or_buffers_changed = 1;
if ((!NILP (echo_area_buffer[0]) && !display_last_displayed_message_p)
|| (!NILP (echo_area_buffer[1]) && display_last_displayed_message_p)
|| (message_cleared_p
&& minibuf_level == 0
&& !MINI_WINDOW_P (XWINDOW (selected_window))))
{
int window_height_changed_p = echo_area_display (0);
must_finish = 1;
if (!display_last_displayed_message_p)
message_cleared_p = 0;
if (fonts_changed_p)
goto retry;
else if (window_height_changed_p)
{
consider_all_windows_p = 1;
++update_mode_lines;
++windows_or_buffers_changed;
if (frame_garbaged)
clear_garbaged_frames ();
}
}
else if (EQ (selected_window, minibuf_window)
&& (current_buffer->clip_changed
|| XFASTINT (w->last_modified) < MODIFF
|| XFASTINT (w->last_overlay_modified) < OVERLAY_MODIFF)
&& resize_mini_window (w, 0))
{
must_finish = 1;
consider_all_windows_p = 1;
++windows_or_buffers_changed;
++update_mode_lines;
if (frame_garbaged)
clear_garbaged_frames ();
}
if (((!NILP (Vtransient_mark_mode)
&& !NILP (XBUFFER (w->buffer)->mark_active))
!= !NILP (w->region_showing))
|| (!NILP (w->region_showing)
&& !EQ (w->region_showing,
Fmarker_position (XBUFFER (w->buffer)->mark))))
CHARPOS (this_line_start_pos) = 0;
tlbufpos = this_line_start_pos;
tlendpos = this_line_end_pos;
if (!consider_all_windows_p
&& CHARPOS (tlbufpos) > 0
&& NILP (w->update_mode_line)
&& !current_buffer->clip_changed
&& FRAME_VISIBLE_P (XFRAME (w->frame))
&& !FRAME_OBSCURED_P (XFRAME (w->frame))
&& this_line_buffer == current_buffer
&& current_buffer == XBUFFER (w->buffer)
&& NILP (w->force_start)
&& PT >= CHARPOS (tlbufpos)
&& PT <= Z - CHARPOS (tlendpos)
&& text_outside_line_unchanged_p (w, CHARPOS (tlbufpos),
CHARPOS (tlendpos)))
{
if (CHARPOS (tlbufpos) > BEGV
&& FETCH_BYTE (BYTEPOS (tlbufpos) - 1) != '\n'
&& (CHARPOS (tlbufpos) == ZV
|| FETCH_BYTE (BYTEPOS (tlbufpos)) == '\n'))
goto cancel;
else if (XFASTINT (w->last_modified) < MODIFF
|| XFASTINT (w->last_overlay_modified) < OVERLAY_MODIFF
|| MINI_WINDOW_P (w))
{
struct it it;
int line_height_before = this_line_pixel_height;
start_display (&it, w, tlbufpos);
if (it.current_x != this_line_start_x)
goto cancel;
TRACE ((stderr, "trying display optimization 1\n"));
w->cursor.vpos = -1;
overlay_arrow_seen = 0;
it.vpos = this_line_vpos;
it.current_y = this_line_y;
it.glyph_row = MATRIX_ROW (w->desired_matrix, this_line_vpos);
display_line (&it);
if (w->cursor.vpos >= 0
&& CHARPOS (this_line_start_pos)
&& CHARPOS (this_line_end_pos) == CHARPOS (tlendpos)
&& this_line_pixel_height == line_height_before)
{
if (it.current_y < it.last_visible_y)
{
struct glyph_row *row
= MATRIX_ROW (w->current_matrix, this_line_vpos + 1);
int delta, delta_bytes;
if (Z - CHARPOS (tlendpos) == ZV)
{
delta = (Z
- CHARPOS (tlendpos)
- MATRIX_ROW_START_CHARPOS (row));
delta_bytes = (Z_BYTE
- BYTEPOS (tlendpos)
- MATRIX_ROW_START_BYTEPOS (row));
}
else
{
delta = (Z
- CHARPOS (tlendpos)
- MATRIX_ROW_START_CHARPOS (row));
delta_bytes = (Z_BYTE
- BYTEPOS (tlendpos)
- MATRIX_ROW_START_BYTEPOS (row));
}
increment_matrix_positions (w->current_matrix,
this_line_vpos + 1,
w->current_matrix->nrows,
delta, delta_bytes);
}
if ((it.glyph_row - 1)->displays_text_p)
{
if (XFASTINT (w->window_end_vpos) < this_line_vpos)
XSETINT (w->window_end_vpos, this_line_vpos);
}
else if (XFASTINT (w->window_end_vpos) == this_line_vpos
&& this_line_vpos > 0)
XSETINT (w->window_end_vpos, this_line_vpos - 1);
w->window_end_valid = Qnil;
w->desired_matrix->no_scrolling_p = 1;
#if GLYPH_DEBUG
*w->desired_matrix->method = 0;
debug_method_add (w, "optimization 1");
#endif
goto update;
}
else
goto cancel;
}
else if (
PT == XFASTINT (w->last_point)
&& 0 <= w->cursor.vpos
&& XINT (w->height) > w->cursor.vpos)
{
if (!must_finish)
{
do_pending_window_change (1);
if (w->cursor_off_p == w->last_cursor_off_p)
goto end_of_redisplay;
}
goto update;
}
else if (! (!NILP (Vtransient_mark_mode)
&& !NILP (current_buffer->mark_active))
&& (EQ (selected_window, current_buffer->last_selected_window)
|| highlight_nonselected_windows)
&& NILP (w->region_showing)
&& NILP (Vshow_trailing_whitespace)
&& !cursor_in_echo_area)
{
struct it it;
struct glyph_row *row;
init_iterator (&it, w, CHARPOS (tlbufpos), BYTEPOS (tlbufpos),
NULL, DEFAULT_FACE_ID);
it.current_x = this_line_start_x;
it.current_y = this_line_y;
it.vpos = this_line_vpos;
move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
if (it.vpos == this_line_vpos
&& (row = MATRIX_ROW (w->current_matrix, this_line_vpos),
row->enabled_p))
{
xassert (this_line_vpos == it.vpos);
xassert (this_line_y == it.current_y);
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
#if GLYPH_DEBUG
*w->desired_matrix->method = 0;
debug_method_add (w, "optimization 3");
#endif
goto update;
}
else
goto cancel;
}
cancel:
SET_MATRIX_ROW_ENABLED_P (w->desired_matrix, this_line_vpos, 0);
}
CHARPOS (this_line_start_pos) = 0;
consider_all_windows_p |= buffer_shared > 1;
++clear_face_cache_count;
if (consider_all_windows_p)
{
Lisp_Object tail, frame;
int i, n = 0, size = 50;
struct frame **updated
= (struct frame **) alloca (size * sizeof *updated);
if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT)
{
clear_face_cache (0);
clear_face_cache_count = 0;
}
buffer_shared = 0;
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
if (FRAME_WINDOW_P (f) || f == sf)
{
if (condemn_scroll_bars_hook)
condemn_scroll_bars_hook (f);
if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
redisplay_windows (FRAME_ROOT_WINDOW (f));
if (judge_scroll_bars_hook)
judge_scroll_bars_hook (f);
if (fonts_changed_p)
goto retry;
if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
{
if (hscroll_windows (f->root_window))
goto retry;
if (interrupt_input)
unrequest_sigio ();
stop_polling ();
set_window_update_flags (XWINDOW (f->root_window), 1);
pause |= update_frame (f, 0, 0);
if (pause)
break;
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;
}
}
}
for (i = 0; i < n; ++i)
{
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);
}
}
else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
{
Lisp_Object mini_window;
struct frame *mini_frame;
redisplay_window (selected_window, 1);
update:
if (fonts_changed_p)
goto retry;
if (interrupt_input)
unrequest_sigio ();
stop_polling ();
if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
{
if (hscroll_windows (selected_window))
goto retry;
XWINDOW (selected_window)->must_be_updated_p = 1;
pause = update_frame (sf, 0, 0);
}
mini_window = FRAME_MINIBUF_WINDOW (sf);
mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
if (mini_frame != sf && FRAME_WINDOW_P (mini_frame))
{
XWINDOW (mini_window)->must_be_updated_p = 1;
pause |= update_frame (mini_frame, 0, 0);
if (!pause && hscroll_windows (mini_window))
goto retry;
}
}
if (pause)
{
CHARPOS (this_line_start_pos) = 0;
if (!NILP (last_arrow_position))
{
last_arrow_position = Qt;
last_arrow_string = Qt;
}
if (!WINDOW_FULL_WIDTH_P (w)
&& !FRAME_WINDOW_P (XFRAME (w->frame)))
update_mode_lines = 1;
}
else
{
if (!consider_all_windows_p)
{
mark_window_display_accurate_1 (w, 1);
last_arrow_position = COERCE_MARKER (Voverlay_arrow_position);
last_arrow_string = Voverlay_arrow_string;
if (frame_up_to_date_hook != 0)
frame_up_to_date_hook (sf);
}
update_mode_lines = 0;
windows_or_buffers_changed = 0;
}
if (interrupt_input)
request_sigio ();
start_polling ();
if (!pause)
{
Lisp_Object tail, frame;
int new_count = 0;
FOR_EACH_FRAME (tail, frame)
{
int this_is_visible = 0;
if (XFRAME (frame)->visible)
this_is_visible = 1;
FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
if (XFRAME (frame)->visible)
this_is_visible = 1;
if (this_is_visible)
new_count++;
}
if (new_count != number_of_visible_frames)
windows_or_buffers_changed++;
}
do_pending_window_change (1);
if (windows_or_buffers_changed && !pause)
goto retry;
end_of_redisplay:;
unbind_to (count, Qnil);
}
void
redisplay_preserve_echo_area (from_where)
int from_where;
{
TRACE ((stderr, "redisplay_preserve_echo_area (%d)\n", from_where));
if (!NILP (echo_area_buffer[1]))
{
display_last_displayed_message_p = 1;
redisplay_internal (1);
display_last_displayed_message_p = 0;
}
else
redisplay_internal (1);
}
static Lisp_Object
unwind_redisplay (old_redisplaying_p)
Lisp_Object old_redisplaying_p;
{
redisplaying_p = XFASTINT (old_redisplaying_p);
return Qnil;
}
static void
mark_window_display_accurate_1 (w, accurate_p)
struct window *w;
int accurate_p;
{
if (BUFFERP (w->buffer))
{
struct buffer *b = XBUFFER (w->buffer);
w->last_modified
= make_number (accurate_p ? BUF_MODIFF (b) : 0);
w->last_overlay_modified
= make_number (accurate_p ? BUF_OVERLAY_MODIFF (b) : 0);
w->last_had_star
= BUF_MODIFF (b) > BUF_SAVE_MODIFF (b) ? Qt : Qnil;
if (accurate_p)
{
b->clip_changed = 0;
b->prevent_redisplay_optimizations_p = 0;
BUF_UNCHANGED_MODIFIED (b) = BUF_MODIFF (b);
BUF_OVERLAY_UNCHANGED_MODIFIED (b) = BUF_OVERLAY_MODIFF (b);
BUF_BEG_UNCHANGED (b) = BUF_GPT (b) - BUF_BEG (b);
BUF_END_UNCHANGED (b) = BUF_Z (b) - BUF_GPT (b);
w->current_matrix->buffer = b;
w->current_matrix->begv = BUF_BEGV (b);
w->current_matrix->zv = BUF_ZV (b);
w->last_cursor = w->cursor;
w->last_cursor_off_p = w->cursor_off_p;
if (w == XWINDOW (selected_window))
w->last_point = make_number (BUF_PT (b));
else
w->last_point = make_number (XMARKER (w->pointm)->charpos);
}
}
if (accurate_p)
{
w->window_end_valid = w->buffer;
#if 0
xassert (XINT (w->window_end_vpos)
< (XINT (w->height)
- (WINDOW_WANTS_MODELINE_P (w) ? 1 : 0)));
#endif
w->update_mode_line = Qnil;
}
}
void
mark_window_display_accurate (window, accurate_p)
Lisp_Object window;
int accurate_p;
{
struct window *w;
for (; !NILP (window); window = w->next)
{
w = XWINDOW (window);
mark_window_display_accurate_1 (w, accurate_p);
if (!NILP (w->vchild))
mark_window_display_accurate (w->vchild, accurate_p);
if (!NILP (w->hchild))
mark_window_display_accurate (w->hchild, accurate_p);
}
if (accurate_p)
{
last_arrow_position = COERCE_MARKER (Voverlay_arrow_position);
last_arrow_string = Voverlay_arrow_string;
}
else
{
last_arrow_position = Qt;
last_arrow_string = Qt;
}
}
Lisp_Object
disp_char_vector (dp, c)
struct Lisp_Char_Table *dp;
int c;
{
int code[4], i;
Lisp_Object val;
if (SINGLE_BYTE_CHAR_P (c))
return (dp->contents[c]);
SPLIT_CHAR (c, code[0], code[1], code[2]);
if (code[1] < 32)
code[1] = -1;
else if (code[2] < 32)
code[2] = -1;
code[0] += 128;
code[3] = -1;
for (i = 0; code[i] >= 0; i++, dp = XCHAR_TABLE (val))
{
val = dp->contents[code[i]];
if (!SUB_CHAR_TABLE_P (val))
return (NILP (val) ? dp->defalt : val);
}
return (dp->defalt);
}
static void
redisplay_windows (window)
Lisp_Object window;
{
while (!NILP (window))
{
struct window *w = XWINDOW (window);
if (!NILP (w->hchild))
redisplay_windows (w->hchild);
else if (!NILP (w->vchild))
redisplay_windows (w->vchild);
else
redisplay_window (window, 0);
window = w->next;
}
}
void
set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
struct window *w;
struct glyph_row *row;
struct glyph_matrix *matrix;
int delta, delta_bytes, dy, dvpos;
{
struct glyph *glyph = row->glyphs[TEXT_AREA];
struct glyph *end = glyph + row->used[TEXT_AREA];
int x = row->x;
int pt_old = PT - delta;
if (row->displays_text_p)
while (glyph < end
&& INTEGERP (glyph->object)
&& glyph->charpos < 0)
{
x += glyph->pixel_width;
++glyph;
}
while (glyph < end
&& !INTEGERP (glyph->object)
&& (!BUFFERP (glyph->object)
|| glyph->charpos < pt_old))
{
x += glyph->pixel_width;
++glyph;
}
w->cursor.hpos = glyph - row->glyphs[TEXT_AREA];
w->cursor.x = x;
w->cursor.vpos = MATRIX_ROW_VPOS (row, matrix) + dvpos;
w->cursor.y = row->y + dy;
if (w == XWINDOW (selected_window))
{
if (!row->continued_p
&& !MATRIX_ROW_CONTINUATION_LINE_P (row)
&& row->x == 0)
{
this_line_buffer = XBUFFER (w->buffer);
CHARPOS (this_line_start_pos)
= MATRIX_ROW_START_CHARPOS (row) + delta;
BYTEPOS (this_line_start_pos)
= MATRIX_ROW_START_BYTEPOS (row) + delta_bytes;
CHARPOS (this_line_end_pos)
= Z - (MATRIX_ROW_END_CHARPOS (row) + delta);
BYTEPOS (this_line_end_pos)
= Z_BYTE - (MATRIX_ROW_END_BYTEPOS (row) + delta_bytes);
this_line_y = w->cursor.y;
this_line_pixel_height = row->height;
this_line_vpos = w->cursor.vpos;
this_line_start_x = row->x;
}
else
CHARPOS (this_line_start_pos) = 0;
}
}
static INLINE struct text_pos
run_window_scroll_functions (window, startp)
Lisp_Object window;
struct text_pos startp;
{
struct window *w = XWINDOW (window);
SET_MARKER_FROM_TEXT_POS (w->start, startp);
if (current_buffer != XBUFFER (w->buffer))
abort ();
if (!NILP (Vwindow_scroll_functions))
{
run_hook_with_args_2 (Qwindow_scroll_functions, window,
make_number (CHARPOS (startp)));
SET_TEXT_POS_FROM_MARKER (startp, w->start);
if (current_buffer != XBUFFER (w->buffer))
set_buffer_internal_1 (XBUFFER (w->buffer));
}
return startp;
}
static int
make_cursor_line_fully_visible (w)
struct window *w;
{
struct glyph_matrix *matrix;
struct glyph_row *row;
int window_height;
if (w->cursor.vpos < 0)
return 1;
matrix = w->desired_matrix;
row = MATRIX_ROW (matrix, w->cursor.vpos);
if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
return 1;
window_height = window_box_height (w);
if (row->height >= window_height)
return 1;
if (MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (w, row))
{
int dy = row->height - row->visible_height;
w->vscroll = 0;
w->cursor.y += dy;
shift_glyph_matrix (w, matrix, 0, matrix->nrows, dy);
}
else
{
int dy = - (row->height - row->visible_height);
w->vscroll = dy;
w->cursor.y += dy;
shift_glyph_matrix (w, matrix, 0, matrix->nrows, dy);
}
if (w == XWINDOW (selected_window))
this_line_y = w->cursor.y;
if (matrix->nrows < required_matrix_height (w))
{
fonts_changed_p = 1;
return 0;
}
return 1;
}
enum
{
SCROLLING_SUCCESS,
SCROLLING_FAILED,
SCROLLING_NEED_LARGER_MATRICES
};
static int
try_scrolling (window, just_this_one_p, scroll_conservatively,
scroll_step, temp_scroll_step)
Lisp_Object window;
int just_this_one_p;
int scroll_conservatively, scroll_step;
int temp_scroll_step;
{
struct window *w = XWINDOW (window);
struct frame *f = XFRAME (w->frame);
struct text_pos scroll_margin_pos;
struct text_pos pos;
struct text_pos startp;
struct it it;
Lisp_Object window_end;
int this_scroll_margin;
int dy = 0;
int scroll_max;
int rc;
int amount_to_scroll = 0;
Lisp_Object aggressive;
int height;
#if GLYPH_DEBUG
debug_method_add (w, "try_scrolling");
#endif
SET_TEXT_POS_FROM_MARKER (startp, w->start);
if (scroll_margin > 0)
{
this_scroll_margin = min (scroll_margin, XINT (w->height) / 4);
this_scroll_margin *= CANON_Y_UNIT (f);
}
else
this_scroll_margin = 0;
if (scroll_step || scroll_conservatively || temp_scroll_step)
scroll_max = max (scroll_step,
max (scroll_conservatively, temp_scroll_step));
else if (NUMBERP (current_buffer->scroll_down_aggressively)
|| NUMBERP (current_buffer->scroll_up_aggressively))
scroll_max = 10;
else
scroll_max = 0;
scroll_max *= CANON_Y_UNIT (f);
window_end = Fwindow_end (window, Qt);
CHARPOS (scroll_margin_pos) = XINT (window_end);
BYTEPOS (scroll_margin_pos) = CHAR_TO_BYTE (CHARPOS (scroll_margin_pos));
if (this_scroll_margin)
{
start_display (&it, w, scroll_margin_pos);
move_it_vertically (&it, - this_scroll_margin);
scroll_margin_pos = it.current.pos;
}
if (PT >= CHARPOS (scroll_margin_pos))
{
int y0;
start_display (&it, w, scroll_margin_pos);
y0 = it.current_y;
move_it_to (&it, PT, 0, it.last_visible_y, -1,
MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
dy = line_bottom_y (&it) - y0;
if (dy > scroll_max)
return SCROLLING_FAILED;
start_display (&it, w, startp);
if (scroll_conservatively)
amount_to_scroll
= max (max (dy, CANON_Y_UNIT (f)),
CANON_Y_UNIT (f) * max (scroll_step, temp_scroll_step));
else if (scroll_step || temp_scroll_step)
amount_to_scroll = scroll_max;
else
{
aggressive = current_buffer->scroll_up_aggressively;
height = (WINDOW_DISPLAY_HEIGHT_NO_MODE_LINE (w)
- WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w));
if (NUMBERP (aggressive))
amount_to_scroll = XFLOATINT (aggressive) * height;
}
if (amount_to_scroll <= 0)
return SCROLLING_FAILED;
move_it_vertically (&it, amount_to_scroll);
startp = it.current.pos;
}
else
{
scroll_margin_pos = startp;
if (this_scroll_margin)
{
start_display (&it, w, startp);
move_it_vertically (&it, this_scroll_margin);
scroll_margin_pos = it.current.pos;
}
if (PT < CHARPOS (scroll_margin_pos))
{
int y0;
SET_TEXT_POS (pos, PT, PT_BYTE);
start_display (&it, w, pos);
y0 = it.current_y;
move_it_to (&it, CHARPOS (scroll_margin_pos), 0,
it.last_visible_y, -1,
MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
dy = it.current_y - y0;
if (dy > scroll_max)
return SCROLLING_FAILED;
start_display (&it, w, startp);
if (scroll_conservatively)
amount_to_scroll =
max (dy, CANON_Y_UNIT (f) * max (scroll_step, temp_scroll_step));
else if (scroll_step || temp_scroll_step)
amount_to_scroll = scroll_max;
else
{
aggressive = current_buffer->scroll_down_aggressively;
height = (WINDOW_DISPLAY_HEIGHT_NO_MODE_LINE (w)
- WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w));
if (NUMBERP (aggressive))
amount_to_scroll = XFLOATINT (aggressive) * height;
}
if (amount_to_scroll <= 0)
return SCROLLING_FAILED;
move_it_vertically (&it, - amount_to_scroll);
startp = it.current.pos;
}
}
startp = run_window_scroll_functions (window, startp);
if (!try_window (window, startp))
rc = SCROLLING_NEED_LARGER_MATRICES;
else if (w->cursor.vpos < 0)
{
clear_glyph_matrix (w->desired_matrix);
rc = SCROLLING_FAILED;
}
else
{
if (!just_this_one_p
|| current_buffer->clip_changed
|| BEG_UNCHANGED < CHARPOS (startp))
w->base_line_number = Qnil;
if (!make_cursor_line_fully_visible (w))
rc = SCROLLING_NEED_LARGER_MATRICES;
else
rc = SCROLLING_SUCCESS;
}
return rc;
}
static int
compute_window_start_on_continuation_line (w)
struct window *w;
{
struct text_pos pos, start_pos;
int window_start_changed_p = 0;
SET_TEXT_POS_FROM_MARKER (start_pos, w->start);
if (CHARPOS (start_pos) > BEGV
&& FETCH_BYTE (BYTEPOS (start_pos) - 1) != '\n')
{
struct it it;
struct glyph_row *row;
if (CHARPOS (start_pos) < BEGV)
SET_TEXT_POS (start_pos, BEGV, BEGV_BYTE);
else if (CHARPOS (start_pos) > ZV)
SET_TEXT_POS (start_pos, ZV, ZV_BYTE);
row = w->desired_matrix->rows + (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0);
init_iterator (&it, w, CHARPOS (start_pos), BYTEPOS (start_pos),
row, DEFAULT_FACE_ID);
reseat_at_previous_visible_line_start (&it);
if (CHARPOS (start_pos) - IT_CHARPOS (it)
< XFASTINT (w->height) * XFASTINT (w->width))
{
int min_distance, distance;
pos = it.current.pos;
min_distance = INFINITY;
while ((distance = abs (CHARPOS (start_pos) - IT_CHARPOS (it))),
distance < min_distance)
{
min_distance = distance;
pos = it.current.pos;
move_it_by_lines (&it, 1, 0);
}
SET_MARKER_FROM_TEXT_POS (w->start, pos);
window_start_changed_p = 1;
}
}
return window_start_changed_p;
}
enum
{
CURSOR_MOVEMENT_SUCCESS,
CURSOR_MOVEMENT_CANNOT_BE_USED,
CURSOR_MOVEMENT_MUST_SCROLL,
CURSOR_MOVEMENT_NEED_LARGER_MATRICES
};
static int
try_cursor_movement (window, startp, scroll_step)
Lisp_Object window;
struct text_pos startp;
int *scroll_step;
{
struct window *w = XWINDOW (window);
struct frame *f = XFRAME (w->frame);
int rc = CURSOR_MOVEMENT_CANNOT_BE_USED;
#if GLYPH_DEBUG
if (inhibit_try_cursor_movement)
return rc;
#endif
if (
PT >= CHARPOS (startp)
&& !current_buffer->clip_changed
&& !update_mode_lines
&& !windows_or_buffers_changed
&& !(!NILP (Vtransient_mark_mode)
&& !NILP (current_buffer->mark_active))
&& NILP (w->region_showing)
&& NILP (Vshow_trailing_whitespace)
&& INTEGERP (w->last_point)
&& !EQ (window, minibuf_window)
&& INTEGERP (w->window_end_vpos)
&& XFASTINT (w->window_end_vpos) < w->current_matrix->nrows
&& (FRAME_WINDOW_P (f)
|| !MARKERP (Voverlay_arrow_position)
|| current_buffer != XMARKER (Voverlay_arrow_position)->buffer))
{
int this_scroll_margin;
struct glyph_row *row = NULL;
#if GLYPH_DEBUG
debug_method_add (w, "cursor movement");
#endif
this_scroll_margin = max (0, scroll_margin);
this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
this_scroll_margin *= CANON_Y_UNIT (f);
if (w->last_cursor.vpos < 0
|| w->last_cursor.vpos >= w->current_matrix->nrows)
rc = CURSOR_MOVEMENT_MUST_SCROLL;
else
{
row = MATRIX_ROW (w->current_matrix, w->last_cursor.vpos);
if (row->mode_line_p)
++row;
if (!row->enabled_p)
rc = CURSOR_MOVEMENT_MUST_SCROLL;
}
if (rc == CURSOR_MOVEMENT_CANNOT_BE_USED)
{
int scroll_p = 0;
int last_y = window_text_bottom_y (w) - this_scroll_margin;
if (PT > XFASTINT (w->last_point))
{
while (MATRIX_ROW_END_CHARPOS (row) < PT
&& MATRIX_ROW_BOTTOM_Y (row) < last_y)
{
xassert (row->enabled_p);
++row;
}
while (MATRIX_ROW_BOTTOM_Y (row) < last_y
&& MATRIX_ROW_END_CHARPOS (row) == PT
&& !cursor_row_p (w, row))
++row;
if (MATRIX_ROW_BOTTOM_Y (row) > last_y
|| PT > MATRIX_ROW_END_CHARPOS (row)
|| (MATRIX_ROW_BOTTOM_Y (row) == last_y
&& PT == MATRIX_ROW_END_CHARPOS (row)
&& !row->ends_at_zv_p
&& !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))
scroll_p = 1;
}
else if (PT < XFASTINT (w->last_point))
{
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)))
&& (row->y > this_scroll_margin
|| CHARPOS (startp) == BEGV))
{
xassert (row->enabled_p);
--row;
}
if (row < w->current_matrix->rows
|| row->mode_line_p)
{
row = w->current_matrix->rows;
if (row->mode_line_p)
++row;
}
while (MATRIX_ROW_BOTTOM_Y (row) < last_y
&& MATRIX_ROW_END_CHARPOS (row) == PT
&& !cursor_row_p (w, row))
++row;
if (row->y < this_scroll_margin
&& CHARPOS (startp) != BEGV)
scroll_p = 1;
}
if (PT < MATRIX_ROW_START_CHARPOS (row)
|| PT > MATRIX_ROW_END_CHARPOS (row))
{
rc = CURSOR_MOVEMENT_MUST_SCROLL;
}
else if (MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
{
if (PT == MATRIX_ROW_END_CHARPOS (row)
&& !row->ends_at_zv_p
&& !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
rc = CURSOR_MOVEMENT_MUST_SCROLL;
else if (row->height > window_box_height (w))
{
*scroll_step = 1;
rc = CURSOR_MOVEMENT_MUST_SCROLL;
}
else
{
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
try_window (window, startp);
if (!make_cursor_line_fully_visible (w))
rc = CURSOR_MOVEMENT_NEED_LARGER_MATRICES;
else
rc = CURSOR_MOVEMENT_SUCCESS;
}
}
else if (scroll_p)
rc = CURSOR_MOVEMENT_MUST_SCROLL;
else
{
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
rc = CURSOR_MOVEMENT_SUCCESS;
}
}
}
return rc;
}
static void
redisplay_window (window, just_this_one_p)
Lisp_Object window;
int just_this_one_p;
{
struct window *w = XWINDOW (window);
struct frame *f = XFRAME (w->frame);
struct buffer *buffer = XBUFFER (w->buffer);
struct buffer *old = current_buffer;
struct text_pos lpoint, opoint, startp;
int update_mode_line;
int tem;
struct it it;
int current_matrix_up_to_date_p = 0;
int temp_scroll_step = 0;
int count = BINDING_STACK_SIZE ();
int rc;
SET_TEXT_POS (lpoint, PT, PT_BYTE);
opoint = lpoint;
xassert (!NILP (w->buffer));
#if GLYPH_DEBUG
*w->desired_matrix->method = 0;
#endif
specbind (Qinhibit_point_motion_hooks, Qt);
reconsider_clip_changes (w, buffer);
update_mode_line = (!NILP (w->update_mode_line)
|| update_mode_lines
|| buffer->clip_changed);
if (MINI_WINDOW_P (w))
{
if (w == XWINDOW (echo_area_window)
&& !NILP (echo_area_buffer[0]))
{
if (update_mode_line)
goto finish_menu_bars;
else
goto finish_scroll_bars;
}
else if (w != XWINDOW (minibuf_window))
{
int yb = window_text_bottom_y (w);
struct glyph_row *row;
int y;
for (y = 0, row = w->desired_matrix->rows;
y < yb;
y += row->height, ++row)
blank_row (w, row, y);
goto finish_scroll_bars;
}
clear_glyph_matrix (w->desired_matrix);
}
set_buffer_internal_1 (XBUFFER (w->buffer));
SET_TEXT_POS (opoint, PT, PT_BYTE);
current_matrix_up_to_date_p
= (!NILP (w->window_end_valid)
&& !current_buffer->clip_changed
&& XFASTINT (w->last_modified) >= MODIFF
&& XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF);
if (windows_or_buffers_changed)
{
if (XMARKER (w->start)->buffer == current_buffer)
compute_window_start_on_continuation_line (w);
w->window_end_valid = Qnil;
}
CHECK_WINDOW_END (w);
if (Z == Z_BYTE && CHARPOS (opoint) != BYTEPOS (opoint))
abort ();
if (BYTEPOS (opoint) < CHARPOS (opoint))
abort ();
if (!NILP (w->column_number_displayed)
&& !(PT == XFASTINT (w->last_point)
&& XFASTINT (w->last_modified) >= MODIFF
&& XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)
&& XFASTINT (w->column_number_displayed) != current_column ())
update_mode_line = 1;
if (!just_this_one_p)
{
struct buffer *current_base, *window_base;
current_base = current_buffer;
window_base = XBUFFER (XWINDOW (selected_window)->buffer);
if (current_base->base_buffer)
current_base = current_base->base_buffer;
if (window_base->base_buffer)
window_base = window_base->base_buffer;
if (current_base == window_base)
buffer_shared++;
}
if (!EQ (window, selected_window))
{
int new_pt = XMARKER (w->pointm)->charpos;
int new_pt_byte = marker_byte_position (w->pointm);
if (new_pt < BEGV)
{
new_pt = BEGV;
new_pt_byte = BEGV_BYTE;
set_marker_both (w->pointm, Qnil, BEGV, BEGV_BYTE);
}
else if (new_pt > (ZV - 1))
{
new_pt = ZV;
new_pt_byte = ZV_BYTE;
set_marker_both (w->pointm, Qnil, ZV, ZV_BYTE);
}
TEMP_SET_PT_BOTH (new_pt, new_pt_byte);
}
if (current_buffer->width_run_cache)
{
struct Lisp_Char_Table *disptab = buffer_display_table ();
if (! disptab_matches_widthtab (disptab,
XVECTOR (current_buffer->width_table)))
{
invalidate_region_cache (current_buffer,
current_buffer->width_run_cache,
BEG, Z);
recompute_width_table (current_buffer, disptab);
}
}
if (XMARKER (w->start)->buffer != current_buffer)
goto recenter;
SET_TEXT_POS_FROM_MARKER (startp, w->start);
if (!NILP (w->optional_new_start)
&& CHARPOS (startp) >= BEGV
&& CHARPOS (startp) <= ZV)
{
w->optional_new_start = Qnil;
start_display (&it, w, startp);
move_it_to (&it, PT, 0, it.last_visible_y, -1,
MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
if (IT_CHARPOS (it) == PT)
w->force_start = Qt;
}
if (!NILP (w->force_start)
|| w->frozen_window_start_p)
{
w->force_start = Qnil;
w->vscroll = 0;
w->window_end_valid = Qnil;
if (!current_matrix_up_to_date_p
|| current_buffer->clip_changed)
w->base_line_number = Qnil;
if (!update_mode_line
|| ! NILP (Vwindow_scroll_functions))
{
update_mode_line = 1;
w->update_mode_line = Qt;
startp = run_window_scroll_functions (window, startp);
}
w->last_modified = make_number (0);
w->last_overlay_modified = make_number (0);
if (CHARPOS (startp) < BEGV)
SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
else if (CHARPOS (startp) > ZV)
SET_TEXT_POS (startp, ZV, ZV_BYTE);
if (!try_window (window, startp))
{
w->force_start = Qt;
clear_glyph_matrix (w->desired_matrix);
goto finish_scroll_bars;
}
if (w->cursor.vpos < 0 && !w->frozen_window_start_p)
{
int window_height;
struct glyph_row *row;
window_height = window_box_height (w) / 2;
row = MATRIX_FIRST_TEXT_ROW (w->desired_matrix);
while (MATRIX_ROW_BOTTOM_Y (row) < window_height)
++row;
TEMP_SET_PT_BOTH (MATRIX_ROW_START_CHARPOS (row),
MATRIX_ROW_START_BYTEPOS (row));
if (w != XWINDOW (selected_window))
set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
else if (current_buffer == old)
SET_TEXT_POS (lpoint, PT, PT_BYTE);
set_cursor_from_row (w, row, w->desired_matrix, 0, 0, 0, 0);
if (!NILP (Vtransient_mark_mode)
&& !NILP (current_buffer->mark_active))
{
clear_glyph_matrix (w->desired_matrix);
if (!try_window (window, startp))
goto need_larger_matrices;
}
}
if (!make_cursor_line_fully_visible (w))
goto need_larger_matrices;
#if GLYPH_DEBUG
debug_method_add (w, "forced window start");
#endif
goto done;
}
if (current_matrix_up_to_date_p
&& (rc = try_cursor_movement (window, startp, &temp_scroll_step),
rc != CURSOR_MOVEMENT_CANNOT_BE_USED))
{
switch (rc)
{
case CURSOR_MOVEMENT_SUCCESS:
goto done;
case CURSOR_MOVEMENT_NEED_LARGER_MATRICES:
goto need_larger_matrices;
case CURSOR_MOVEMENT_MUST_SCROLL:
goto try_to_scroll;
default:
abort ();
}
}
else if (!NILP (w->start_at_line_beg)
&& !(CHARPOS (startp) <= BEGV
|| FETCH_BYTE (BYTEPOS (startp) - 1) == '\n'))
{
#if GLYPH_DEBUG
debug_method_add (w, "recenter 1");
#endif
goto recenter;
}
else if ((tem = try_window_id (w)) != 0)
{
#if GLYPH_DEBUG
debug_method_add (w, "try_window_id %d", tem);
#endif
if (fonts_changed_p)
goto need_larger_matrices;
if (tem > 0)
goto done;
}
else if (CHARPOS (startp) >= BEGV
&& CHARPOS (startp) <= ZV
&& PT >= CHARPOS (startp)
&& (CHARPOS (startp) < ZV
|| CHARPOS (startp) == BEGV
|| (XFASTINT (w->last_modified) >= MODIFF
&& XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)))
{
#if GLYPH_DEBUG
debug_method_add (w, "same window start");
#endif
if (!current_matrix_up_to_date_p
|| !NILP (Vwindow_scroll_functions)
|| MINI_WINDOW_P (w)
|| !try_window_reusing_current_matrix (w))
{
IF_DEBUG (debug_method_add (w, "1"));
try_window (window, startp);
}
if (fonts_changed_p)
goto need_larger_matrices;
if (w->cursor.vpos >= 0)
{
if (!just_this_one_p
|| current_buffer->clip_changed
|| BEG_UNCHANGED < CHARPOS (startp))
w->base_line_number = Qnil;
if (!make_cursor_line_fully_visible (w))
goto need_larger_matrices;
goto done;
}
else
clear_glyph_matrix (w->desired_matrix);
}
try_to_scroll:
w->last_modified = make_number (0);
w->last_overlay_modified = make_number (0);
if (!update_mode_line)
{
update_mode_line = 1;
w->update_mode_line = Qt;
}
if ((scroll_conservatively
|| scroll_step
|| temp_scroll_step
|| NUMBERP (current_buffer->scroll_up_aggressively)
|| NUMBERP (current_buffer->scroll_down_aggressively))
&& !current_buffer->clip_changed
&& CHARPOS (startp) >= BEGV
&& CHARPOS (startp) <= ZV)
{
int rc = try_scrolling (window, just_this_one_p,
scroll_conservatively,
scroll_step,
temp_scroll_step);
switch (rc)
{
case SCROLLING_SUCCESS:
goto done;
case SCROLLING_NEED_LARGER_MATRICES:
goto need_larger_matrices;
case SCROLLING_FAILED:
break;
default:
abort ();
}
}
recenter:
#if GLYPH_DEBUG
debug_method_add (w, "recenter");
#endif
if (!current_matrix_up_to_date_p
|| current_buffer->clip_changed)
w->base_line_number = Qnil;
init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
it.current_y = it.last_visible_y;
move_it_vertically_backward (&it, window_box_height (w) / 2);
xassert (IT_CHARPOS (it) >= BEGV);
if (it.current_y <= 0)
{
init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
move_it_vertically (&it, 0);
xassert (IT_CHARPOS (it) <= PT);
it.current_y = 0;
}
it.current_x = it.hpos = 0;
set_marker_both (w->start, Qnil, IT_CHARPOS (it), IT_BYTEPOS (it));
startp = run_window_scroll_functions (window, it.current.pos);
if (!current_matrix_up_to_date_p
|| windows_or_buffers_changed
|| !NILP (Vwindow_scroll_functions)
|| !just_this_one_p
|| MINI_WINDOW_P (w)
|| !try_window_reusing_current_matrix (w))
try_window (window, startp);
if (fonts_changed_p)
goto need_larger_matrices;
if (w->cursor.vpos < 0)
{
if (!NILP (w->window_end_valid)
&& PT >= Z - XFASTINT (w->window_end_pos))
{
clear_glyph_matrix (w->desired_matrix);
move_it_by_lines (&it, 1, 0);
try_window (window, it.current.pos);
}
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);
}
else
{
}
}
if (w->cursor.vpos < 0)
{
struct glyph_row *row = w->current_matrix->rows;
if (row->mode_line_p)
++row;
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
}
if (!make_cursor_line_fully_visible (w))
goto need_larger_matrices;
done:
SET_TEXT_POS_FROM_MARKER (startp, w->start);
w->start_at_line_beg = ((CHARPOS (startp) == BEGV
|| FETCH_BYTE (BYTEPOS (startp) - 1) == '\n')
? Qt : Qnil);
if ((update_mode_line
|| (!just_this_one_p
&& !FRAME_WINDOW_P (f)
&& !WINDOW_FULL_WIDTH_P (w))
|| INTEGERP (w->base_line_pos)
|| (!NILP (w->column_number_displayed)
&& XFASTINT (w->column_number_displayed) != current_column ()))
&& (WINDOW_WANTS_MODELINE_P (w)
|| WINDOW_WANTS_HEADER_LINE_P (w)))
{
display_mode_lines (w);
if (WINDOW_WANTS_MODELINE_P (w)
&& CURRENT_MODE_LINE_HEIGHT (w) != DESIRED_MODE_LINE_HEIGHT (w))
{
fonts_changed_p = 1;
MATRIX_MODE_LINE_ROW (w->current_matrix)->height
= DESIRED_MODE_LINE_HEIGHT (w);
}
if (WINDOW_WANTS_HEADER_LINE_P (w)
&& CURRENT_HEADER_LINE_HEIGHT (w) != DESIRED_HEADER_LINE_HEIGHT (w))
{
fonts_changed_p = 1;
MATRIX_HEADER_LINE_ROW (w->current_matrix)->height
= DESIRED_HEADER_LINE_HEIGHT (w);
}
if (fonts_changed_p)
goto need_larger_matrices;
}
if (!line_number_displayed
&& !BUFFERP (w->base_line_pos))
{
w->base_line_pos = Qnil;
w->base_line_number = Qnil;
}
finish_menu_bars:
if (update_mode_line
&& EQ (FRAME_SELECTED_WINDOW (f), window))
{
int redisplay_menu_p = 0;
if (FRAME_WINDOW_P (f))
{
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
redisplay_menu_p = FRAME_EXTERNAL_MENU_BAR (f);
#else
redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0;
#endif
}
else
redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0;
if (redisplay_menu_p)
display_menu_bar (w);
#ifdef HAVE_WINDOW_SYSTEM
if (WINDOWP (f->tool_bar_window)
&& (FRAME_TOOL_BAR_LINES (f) > 0
|| auto_resize_tool_bars_p))
redisplay_tool_bar (f);
#endif
}
need_larger_matrices:
;
finish_scroll_bars:
if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
{
int start, end, whole;
if (!MINI_WINDOW_P (w)
|| (w == XWINDOW (minibuf_window)
&& NILP (echo_area_buffer[0])))
{
whole = ZV - BEGV;
start = marker_position (w->start) - BEGV;
end = (Z - XFASTINT (w->window_end_pos)) - BEGV;
if (end < start)
end = start;
if (whole < (end - start))
whole = end - start;
}
else
start = end = whole = 0;
set_vertical_scroll_bar_hook (w, end - start, whole, start);
redeem_scroll_bar_hook (w);
}
TEMP_SET_PT_BOTH (CHARPOS (opoint), BYTEPOS (opoint));
set_buffer_internal_1 (old);
TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
unbind_to (count, Qnil);
}
int
try_window (window, pos)
Lisp_Object window;
struct text_pos pos;
{
struct window *w = XWINDOW (window);
struct it it;
struct glyph_row *last_text_row = NULL;
set_marker_both (w->start, Qnil, CHARPOS (pos), BYTEPOS (pos));
w->cursor.vpos = -1;
overlay_arrow_seen = 0;
start_display (&it, w, pos);
while (it.current_y < it.last_visible_y)
{
if (display_line (&it))
last_text_row = it.glyph_row - 1;
if (fonts_changed_p)
return 0;
}
if (XFASTINT (w->window_end_pos) <= 0
&& Z != IT_CHARPOS (it))
w->update_mode_line = Qt;
if (last_text_row)
{
xassert (MATRIX_ROW_DISPLAYS_TEXT_P (last_text_row));
w->window_end_bytepos
= Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
w->window_end_pos
= make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row));
w->window_end_vpos
= make_number (MATRIX_ROW_VPOS (last_text_row, w->desired_matrix));
xassert (MATRIX_ROW (w->desired_matrix, XFASTINT (w->window_end_vpos))
->displays_text_p);
}
else
{
w->window_end_bytepos = 0;
w->window_end_pos = w->window_end_vpos = make_number (0);
}
w->window_end_valid = Qnil;
return 1;
}
static int
try_window_reusing_current_matrix (w)
struct window *w;
{
struct frame *f = XFRAME (w->frame);
struct glyph_row *row, *bottom_row;
struct it it;
struct run run;
struct text_pos start, new_start;
int nrows_scrolled, i;
struct glyph_row *last_text_row;
struct glyph_row *last_reused_text_row;
struct glyph_row *start_row;
int start_vpos, min_y, max_y;
#if GLYPH_DEBUG
if (inhibit_try_window_reusing)
return 0;
#endif
if (
!FRAME_WINDOW_P (f)
|| windows_or_buffers_changed)
return 0;
if ((!NILP (Vtransient_mark_mode)
&& !NILP (current_buffer->mark_active))
|| !NILP (w->region_showing)
|| !NILP (Vshow_trailing_whitespace))
return 0;
if (WINDOW_WANTS_HEADER_LINE_P (w)
!= MATRIX_HEADER_LINE_ROW (w->current_matrix)->mode_line_p)
return 0;
start_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
if (w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (start_row))
return 0;
SET_TEXT_POS_FROM_MARKER (new_start, w->start);
start = start_row->start.pos;
start_vpos = MATRIX_ROW_VPOS (start_row, w->current_matrix);
clear_glyph_matrix (w->desired_matrix);
if (CHARPOS (new_start) <= CHARPOS (start))
{
int first_row_y;
if (in_ellipses_for_invisible_text_p (&start_row->start, w))
return 0;
IF_DEBUG (debug_method_add (w, "twu1"));
start_display (&it, w, new_start);
first_row_y = it.current_y;
w->cursor.vpos = -1;
last_text_row = last_reused_text_row = NULL;
while (it.current_y < it.last_visible_y
&& IT_CHARPOS (it) < CHARPOS (start)
&& !fonts_changed_p)
if (display_line (&it))
last_text_row = it.glyph_row - 1;
if (it.current_y < it.last_visible_y)
{
nrows_scrolled = it.vpos;
if (w->cursor.vpos < 0)
{
int dy = it.current_y - first_row_y;
row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
row = row_containing_pos (w, PT, row, NULL, dy);
if (row)
set_cursor_from_row (w, row, w->current_matrix, 0, 0,
dy, nrows_scrolled);
else
{
clear_glyph_matrix (w->desired_matrix);
return 0;
}
}
run.current_y = first_row_y;
run.desired_y = it.current_y;
run.height = it.last_visible_y - it.current_y;
if (run.height > 0 && run.current_y != run.desired_y)
{
update_begin (f);
rif->update_window_begin_hook (w);
rif->clear_mouse_face (w);
rif->scroll_run_hook (w, &run);
rif->update_window_end_hook (w, 0, 0);
update_end (f);
}
bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
rotate_matrix (w->current_matrix,
start_vpos,
MATRIX_ROW_VPOS (bottom_row, w->current_matrix),
nrows_scrolled);
for (i = 0; i < it.vpos; ++i)
(start_row + i)->enabled_p = 0;
min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
max_y = it.last_visible_y;
for (row = start_row + nrows_scrolled;
row < bottom_row;
++row)
{
row->y = it.current_y;
row->visible_height = row->height;
if (row->y < min_y)
row->visible_height -= min_y - row->y;
if (row->y + row->height > max_y)
row->visible_height -= row->y + row->height - max_y;
it.current_y += row->height;
if (MATRIX_ROW_DISPLAYS_TEXT_P (row))
last_reused_text_row = row;
if (MATRIX_ROW_BOTTOM_Y (row) >= it.last_visible_y)
break;
}
for (++row; row < bottom_row; ++row)
row->enabled_p = 0;
}
if (last_reused_text_row)
{
w->window_end_bytepos
= Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_reused_text_row);
w->window_end_pos
= make_number (Z - MATRIX_ROW_END_CHARPOS (last_reused_text_row));
w->window_end_vpos
= make_number (MATRIX_ROW_VPOS (last_reused_text_row,
w->current_matrix));
}
else if (last_text_row)
{
w->window_end_bytepos
= Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
w->window_end_pos
= make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row));
w->window_end_vpos
= make_number (MATRIX_ROW_VPOS (last_text_row, w->desired_matrix));
}
else
{
w->window_end_bytepos = 0;
w->window_end_pos = w->window_end_vpos = make_number (0);
}
w->window_end_valid = Qnil;
w->desired_matrix->no_scrolling_p = 1;
#if GLYPH_DEBUG
debug_method_add (w, "try_window_reusing_current_matrix 1");
#endif
return 1;
}
else if (CHARPOS (new_start) > CHARPOS (start))
{
struct glyph_row *pt_row, *row;
struct glyph_row *first_reusable_row;
struct glyph_row *first_row_to_display;
int dy;
int yb = window_text_bottom_y (w);
first_reusable_row = start_row;
while (first_reusable_row->enabled_p
&& MATRIX_ROW_BOTTOM_Y (first_reusable_row) < yb
&& (MATRIX_ROW_START_CHARPOS (first_reusable_row)
< CHARPOS (new_start)))
++first_reusable_row;
if (MATRIX_ROW_BOTTOM_Y (first_reusable_row) >= yb
|| !first_reusable_row->enabled_p
|| (MATRIX_ROW_START_CHARPOS (first_reusable_row)
!= CHARPOS (new_start)))
return 0;
pt_row = NULL;
for (first_row_to_display = first_reusable_row;
MATRIX_ROW_BOTTOM_Y (first_row_to_display) < yb;
++first_row_to_display)
{
if (PT >= MATRIX_ROW_START_CHARPOS (first_row_to_display)
&& PT < MATRIX_ROW_END_CHARPOS (first_row_to_display))
pt_row = first_row_to_display;
}
xassert (first_row_to_display->y < yb);
init_to_row_start (&it, w, first_row_to_display);
nrows_scrolled = (MATRIX_ROW_VPOS (first_reusable_row, w->current_matrix)
- start_vpos);
it.vpos = (MATRIX_ROW_VPOS (first_row_to_display, w->current_matrix)
- nrows_scrolled);
it.current_y = (first_row_to_display->y - first_reusable_row->y
+ WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w));
it.glyph_row = MATRIX_ROW (w->desired_matrix, it.vpos);
if (pt_row == NULL)
w->cursor.vpos = -1;
last_text_row = NULL;
while (it.current_y < it.last_visible_y && !fonts_changed_p)
if (display_line (&it))
last_text_row = it.glyph_row - 1;
if (w->cursor.vpos < 0)
{
clear_glyph_matrix (w->desired_matrix);
return 0;
}
if (pt_row)
{
w->cursor.vpos -= MATRIX_ROW_VPOS (first_reusable_row,
w->current_matrix);
w->cursor.y -= first_reusable_row->y;
}
run.current_y = first_reusable_row->y;
run.desired_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
run.height = it.last_visible_y - run.current_y;
dy = run.current_y - run.desired_y;
if (run.height)
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
update_begin (f);
rif->update_window_begin_hook (w);
rif->clear_mouse_face (w);
rif->scroll_run_hook (w, &run);
rif->update_window_end_hook (w, 0, 0);
update_end (f);
}
bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
max_y = it.last_visible_y;
for (row = first_reusable_row; row < first_row_to_display; ++row)
{
row->y -= dy;
row->visible_height = row->height;
if (row->y < min_y)
row->visible_height -= min_y - row->y;
if (row->y + row->height > max_y)
row->visible_height -= row->y + row->height - max_y;
}
xassert (nrows_scrolled > 0);
rotate_matrix (w->current_matrix,
start_vpos,
MATRIX_ROW_VPOS (bottom_row, w->current_matrix),
-nrows_scrolled);
for (row -= nrows_scrolled; row < bottom_row; ++row)
row->enabled_p = 0;
if (last_text_row)
{
w->window_end_bytepos
= Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
w->window_end_pos
= make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row));
w->window_end_vpos
= make_number (MATRIX_ROW_VPOS (last_text_row, w->desired_matrix));
}
else
{
w->window_end_vpos
= make_number (XFASTINT (w->window_end_vpos) - nrows_scrolled);
}
w->window_end_valid = Qnil;
w->desired_matrix->no_scrolling_p = 1;
#if GLYPH_DEBUG
debug_method_add (w, "try_window_reusing_current_matrix 2");
#endif
return 1;
}
return 0;
}
static struct glyph_row *find_last_unchanged_at_beg_row P_ ((struct window *));
static struct glyph_row *find_first_unchanged_at_end_row P_ ((struct window *,
int *, int *));
static struct glyph_row *
find_last_row_displaying_text P_ ((struct glyph_matrix *, struct it *,
struct glyph_row *));
static struct glyph_row *
find_last_row_displaying_text (matrix, it, start)
struct glyph_matrix *matrix;
struct it *it;
struct glyph_row *start;
{
struct glyph_row *row, *row_found;
row_found = NULL;
row = start ? start : MATRIX_FIRST_TEXT_ROW (matrix);
while (MATRIX_ROW_DISPLAYS_TEXT_P (row))
{
xassert (row->enabled_p);
row_found = row;
if (MATRIX_ROW_BOTTOM_Y (row) >= it->last_visible_y)
break;
++row;
}
return row_found;
}
static struct glyph_row *
find_last_unchanged_at_beg_row (w)
struct window *w;
{
int first_changed_pos = BEG + BEG_UNCHANGED;
struct glyph_row *row;
struct glyph_row *row_found = NULL;
int yb = window_text_bottom_y (w);
row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
while (MATRIX_ROW_DISPLAYS_TEXT_P (row)
&& MATRIX_ROW_START_CHARPOS (row) < first_changed_pos)
{
if (
MATRIX_ROW_END_CHARPOS (row) <= first_changed_pos
&& !row->ends_at_zv_p
&& !(MATRIX_ROW_END_CHARPOS (row) == first_changed_pos
&& row->continued_p))
row_found = row;
if (MATRIX_ROW_BOTTOM_Y (row) >= yb)
break;
++row;
}
return row_found;
}
static struct glyph_row *
find_first_unchanged_at_end_row (w, delta, delta_bytes)
struct window *w;
int *delta, *delta_bytes;
{
struct glyph_row *row;
struct glyph_row *row_found = NULL;
*delta = *delta_bytes = 0;
if (NILP (w->window_end_valid))
abort ();
if (XFASTINT (w->window_end_pos) >= END_UNCHANGED)
return NULL;
row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
if (MATRIX_ROW_DISPLAYS_TEXT_P (row))
{
int Z_old = MATRIX_ROW_END_CHARPOS (row) + XFASTINT (w->window_end_pos);
int Z_BYTE_old = MATRIX_ROW_END_BYTEPOS (row) + w->window_end_bytepos;
int last_unchanged_pos, last_unchanged_pos_old;
struct glyph_row *first_text_row
= MATRIX_FIRST_TEXT_ROW (w->current_matrix);
*delta = Z - Z_old;
*delta_bytes = Z_BYTE - Z_BYTE_old;
last_unchanged_pos = Z - END_UNCHANGED + BEG;
last_unchanged_pos_old = last_unchanged_pos - *delta;
for (; row > first_text_row; --row)
{
if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
abort ();
if (MATRIX_ROW_START_CHARPOS (row) >= last_unchanged_pos_old)
row_found = row;
}
}
if (row_found && !MATRIX_ROW_DISPLAYS_TEXT_P (row_found))
abort ();
return row_found;
}
static void
sync_frame_with_window_matrix_rows (w)
struct window *w;
{
struct frame *f = XFRAME (w->frame);
struct glyph_row *window_row, *window_row_end, *frame_row;
xassert (NILP (w->hchild) && NILP (w->vchild));
xassert (WINDOW_FULL_WIDTH_P (w));
xassert (!FRAME_WINDOW_P (f));
window_row = w->current_matrix->rows;
window_row_end = window_row + w->current_matrix->nrows;
frame_row = f->current_matrix->rows + XFASTINT (w->top);
while (window_row < window_row_end)
{
int area;
for (area = LEFT_MARGIN_AREA; area <= LAST_AREA; ++area)
frame_row->glyphs[area] = window_row->glyphs[area];
if (!window_row->enabled_p)
frame_row->enabled_p = 0;
++window_row, ++frame_row;
}
}
struct glyph_row *
row_containing_pos (w, charpos, start, end, dy)
struct window *w;
int charpos;
struct glyph_row *start, *end;
int dy;
{
struct glyph_row *row = start;
int last_y;
if (row->mode_line_p)
++row;
if ((end && row >= end) || !row->enabled_p)
return NULL;
last_y = window_text_bottom_y (w) - dy;
while ((end == NULL || row < end)
&& MATRIX_ROW_BOTTOM_Y (row) < last_y
&& (MATRIX_ROW_END_CHARPOS (row) < charpos
|| (MATRIX_ROW_END_CHARPOS (row) == charpos
&& !row->ends_at_zv_p
&& !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))))
++row;
if ((end && row >= end)
|| charpos < MATRIX_ROW_START_CHARPOS (row)
|| charpos > MATRIX_ROW_END_CHARPOS (row))
row = NULL;
return row;
}
static int
try_window_id (w)
struct window *w;
{
struct frame *f = XFRAME (w->frame);
struct glyph_matrix *current_matrix = w->current_matrix;
struct glyph_matrix *desired_matrix = w->desired_matrix;
struct glyph_row *last_unchanged_at_beg_row;
struct glyph_row *first_unchanged_at_end_row;
struct glyph_row *row;
struct glyph_row *bottom_row;
int bottom_vpos;
struct it it;
int delta = 0, delta_bytes = 0, stop_pos, dvpos, dy;
struct text_pos start_pos;
struct run run;
int first_unchanged_at_end_vpos = 0;
struct glyph_row *last_text_row, *last_text_row_at_end;
struct text_pos start;
int first_changed_charpos, last_changed_charpos;
#if GLYPH_DEBUG
if (inhibit_try_window_id)
return 0;
#endif
#if 0
#define GIVE_UP(X) \
do { \
fprintf (stderr, "try_window_id give up %d\n", (X)); \
return 0; \
} while (0)
#else
#define GIVE_UP(X) return 0
#endif
SET_TEXT_POS_FROM_MARKER (start, w->start);
if (MINI_WINDOW_P (w))
GIVE_UP (1);
if (windows_or_buffers_changed)
GIVE_UP (2);
if (current_buffer->clip_changed)
GIVE_UP (3);
if (!FRAME_WINDOW_P (f)
&& (!line_ins_del_ok
|| !WINDOW_FULL_WIDTH_P (w)))
GIVE_UP (4);
if (PT < CHARPOS (start))
GIVE_UP (5);
if (XFASTINT (w->last_modified) == 0)
GIVE_UP (6);
if (XFASTINT (w->hscroll) != 0)
GIVE_UP (7);
if (NILP (w->window_end_valid))
GIVE_UP (8);
if (!NILP (Vtransient_mark_mode)
&& !NILP (current_buffer->mark_active))
GIVE_UP (9);
if (!NILP (Vshow_trailing_whitespace))
GIVE_UP (11);
if (!NILP (w->region_showing))
GIVE_UP (10);
if (!EQ (last_arrow_position, COERCE_MARKER (Voverlay_arrow_position))
|| !EQ (last_arrow_string, Voverlay_arrow_string))
GIVE_UP (12);
if (MODIFF > SAVE_MODIFF
|| BEG_UNCHANGED + END_UNCHANGED > Z_BYTE)
{
if (GPT - BEG < BEG_UNCHANGED)
BEG_UNCHANGED = GPT - BEG;
if (Z - GPT < END_UNCHANGED)
END_UNCHANGED = Z - GPT;
}
first_changed_charpos = BEG + BEG_UNCHANGED;
last_changed_charpos = Z - END_UNCHANGED;
row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
if (MATRIX_ROW_DISPLAYS_TEXT_P (row)
&& ((last_changed_charpos < CHARPOS (start)
&& CHARPOS (start) == BEGV)
|| (last_changed_charpos < CHARPOS (start) - 1
&& FETCH_BYTE (BYTEPOS (start) - 1) == '\n')))
{
int Z_old, delta, Z_BYTE_old, delta_bytes;
struct glyph_row *r0;
Z_old = MATRIX_ROW_END_CHARPOS (row) + XFASTINT (w->window_end_pos);
Z_BYTE_old = MATRIX_ROW_END_BYTEPOS (row) + w->window_end_bytepos;
delta = Z - Z_old;
delta_bytes = Z_BYTE - Z_BYTE_old;
if (PT >= MATRIX_ROW_END_CHARPOS (row) + delta)
GIVE_UP (13);
r0 = MATRIX_FIRST_TEXT_ROW (current_matrix);
if (CHARPOS (start) == MATRIX_ROW_START_CHARPOS (r0) + delta
&& BYTEPOS (start) == MATRIX_ROW_START_BYTEPOS (r0) + delta_bytes)
{
if (delta || delta_bytes)
{
struct glyph_row *r1
= MATRIX_BOTTOM_TEXT_ROW (current_matrix, w);
increment_matrix_positions (w->current_matrix,
MATRIX_ROW_VPOS (r0, current_matrix),
MATRIX_ROW_VPOS (r1, current_matrix),
delta, delta_bytes);
}
row = row_containing_pos (w, PT, r0, NULL, 0);
set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0);
return 1;
}
}
if (first_changed_charpos >= MATRIX_ROW_END_CHARPOS (row)
&& (current_matrix->zv > MATRIX_ROW_END_CHARPOS (row)
|| first_changed_charpos == last_changed_charpos))
{
struct glyph_row *r0;
if (PT >= MATRIX_ROW_END_CHARPOS (row))
GIVE_UP (14);
r0 = MATRIX_FIRST_TEXT_ROW (current_matrix);
if (TEXT_POS_EQUAL_P (start, r0->start.pos))
{
w->window_end_pos
= make_number (Z - MATRIX_ROW_END_CHARPOS (row));
w->window_end_bytepos
= Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
row = row_containing_pos (w, PT, r0, NULL, 0);
set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0);
return 2;
}
}
if (CHARPOS (start) >= first_changed_charpos
&& CHARPOS (start) <= last_changed_charpos)
GIVE_UP (15);
row = MATRIX_FIRST_TEXT_ROW (current_matrix);
if (!TEXT_POS_EQUAL_P (start, row->start.pos))
GIVE_UP (16);
row = MATRIX_ROW (current_matrix, XFASTINT (w->window_end_vpos));
if (MATRIX_ROW_START_CHARPOS (row) == MATRIX_ROW_END_CHARPOS (row))
GIVE_UP (20);
last_unchanged_at_beg_row = find_last_unchanged_at_beg_row (w);
if (last_unchanged_at_beg_row)
{
while ((MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (last_unchanged_at_beg_row)
|| last_unchanged_at_beg_row->ends_in_newline_from_string_p)
&& last_unchanged_at_beg_row > w->current_matrix->rows)
--last_unchanged_at_beg_row;
if (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (last_unchanged_at_beg_row))
GIVE_UP (17);
if (init_to_row_end (&it, w, last_unchanged_at_beg_row) == 0)
GIVE_UP (18);
start_pos = it.current.pos;
it.vpos = 1 + MATRIX_ROW_VPOS (last_unchanged_at_beg_row,
current_matrix);
it.glyph_row = MATRIX_ROW (desired_matrix, it.vpos);
it.current_y = MATRIX_ROW_BOTTOM_Y (last_unchanged_at_beg_row);
xassert (it.hpos == 0 && it.current_x == 0);
}
else
{
start_display (&it, w, start);
start_pos = it.current.pos;
}
first_unchanged_at_end_row
= find_first_unchanged_at_end_row (w, &delta, &delta_bytes);
IF_DEBUG (debug_delta = delta);
IF_DEBUG (debug_delta_bytes = delta_bytes);
stop_pos = 0;
if (first_unchanged_at_end_row)
{
#if GLYPH_DEBUG
xassert (last_unchanged_at_beg_row == NULL
|| first_unchanged_at_end_row >= last_unchanged_at_beg_row);
#else
if (last_unchanged_at_beg_row
&& first_unchanged_at_end_row < last_unchanged_at_beg_row)
GIVE_UP (20);
#endif
while (MATRIX_ROW_CONTINUATION_LINE_P (first_unchanged_at_end_row)
&& MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row)
&& (MATRIX_ROW_BOTTOM_Y (first_unchanged_at_end_row)
< it.last_visible_y))
++first_unchanged_at_end_row;
if (!MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row)
|| (MATRIX_ROW_BOTTOM_Y (first_unchanged_at_end_row)
>= it.last_visible_y))
first_unchanged_at_end_row = NULL;
else
{
stop_pos = (MATRIX_ROW_START_CHARPOS (first_unchanged_at_end_row)
+ delta);
first_unchanged_at_end_vpos
= MATRIX_ROW_VPOS (first_unchanged_at_end_row, current_matrix);
xassert (stop_pos >= Z - END_UNCHANGED);
}
}
else if (last_unchanged_at_beg_row == NULL)
GIVE_UP (19);
#if GLYPH_DEBUG
xassert (first_unchanged_at_end_row == NULL
|| MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row));
debug_last_unchanged_at_beg_vpos
= (last_unchanged_at_beg_row
? MATRIX_ROW_VPOS (last_unchanged_at_beg_row, current_matrix)
: -1);
debug_first_unchanged_at_end_vpos = first_unchanged_at_end_vpos;
#endif
w->cursor.vpos = -1;
last_text_row = NULL;
overlay_arrow_seen = 0;
while (it.current_y < it.last_visible_y
&& !fonts_changed_p
&& (first_unchanged_at_end_row == NULL
|| IT_CHARPOS (it) < stop_pos))
{
if (display_line (&it))
last_text_row = it.glyph_row - 1;
}
if (fonts_changed_p)
return -1;
if (first_unchanged_at_end_row
&& it.current_y < it.last_visible_y)
{
dvpos = (it.vpos
- MATRIX_ROW_VPOS (first_unchanged_at_end_row,
current_matrix));
dy = it.current_y - first_unchanged_at_end_row->y;
run.current_y = first_unchanged_at_end_row->y;
run.desired_y = run.current_y + dy;
run.height = it.last_visible_y - max (run.current_y, run.desired_y);
}
else
{
delta = dvpos = dy = run.current_y = run.desired_y = run.height = 0;
first_unchanged_at_end_row = NULL;
}
IF_DEBUG (debug_dvpos = dvpos; debug_dy = dy);
if (w->cursor.vpos < 0)
{
if (PT < CHARPOS (start_pos)
&& last_unchanged_at_beg_row)
{
row = row_containing_pos (w, PT,
MATRIX_FIRST_TEXT_ROW (w->current_matrix),
last_unchanged_at_beg_row + 1, 0);
if (row)
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
}
else if (first_unchanged_at_end_row)
{
row = row_containing_pos (w, PT - delta,
first_unchanged_at_end_row, NULL, 0);
if (row)
set_cursor_from_row (w, row, w->current_matrix, delta,
delta_bytes, dy, dvpos);
}
if (w->cursor.vpos < 0)
{
clear_glyph_matrix (w->desired_matrix);
return -1;
}
}
{
int this_scroll_margin, cursor_height;
this_scroll_margin = max (0, scroll_margin);
this_scroll_margin = min (this_scroll_margin,
XFASTINT (w->height) / 4);
this_scroll_margin *= CANON_Y_UNIT (it.f);
cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height;
if ((w->cursor.y < this_scroll_margin
&& CHARPOS (start) > BEGV)
|| w->cursor.y + cursor_height > it.last_visible_y)
{
w->cursor.vpos = -1;
clear_glyph_matrix (w->desired_matrix);
return -1;
}
}
if (dy && run.height)
{
update_begin (f);
if (FRAME_WINDOW_P (f))
{
rif->update_window_begin_hook (w);
rif->clear_mouse_face (w);
rif->scroll_run_hook (w, &run);
rif->update_window_end_hook (w, 0, 0);
}
else
{
int first_unchanged_at_end_vpos
= MATRIX_ROW_VPOS (first_unchanged_at_end_row, w->current_matrix);
int from = XFASTINT (w->top) + first_unchanged_at_end_vpos;
int end = (XFASTINT (w->top)
+ (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0)
+ window_internal_height (w));
if (dvpos > 0)
{
set_terminal_window (end);
if (!scroll_region_ok)
ins_del_lines (end - dvpos, -dvpos);
ins_del_lines (from, dvpos);
}
else if (dvpos < 0)
{
set_terminal_window (end);
ins_del_lines (from + dvpos, dvpos);
if (!scroll_region_ok)
ins_del_lines (end + dvpos, -dvpos);
}
set_terminal_window (0);
}
update_end (f);
}
bottom_row = MATRIX_BOTTOM_TEXT_ROW (current_matrix, w);
bottom_vpos = MATRIX_ROW_VPOS (bottom_row, current_matrix);
if (dvpos < 0)
{
rotate_matrix (current_matrix, first_unchanged_at_end_vpos + dvpos,
bottom_vpos, dvpos);
enable_glyph_matrix_rows (current_matrix, bottom_vpos + dvpos,
bottom_vpos, 0);
}
else if (dvpos > 0)
{
rotate_matrix (current_matrix, first_unchanged_at_end_vpos,
bottom_vpos, dvpos);
enable_glyph_matrix_rows (current_matrix, first_unchanged_at_end_vpos,
first_unchanged_at_end_vpos + dvpos, 0);
}
if (!FRAME_WINDOW_P (f))
sync_frame_with_window_matrix_rows (w);
if (delta)
increment_matrix_positions (current_matrix,
first_unchanged_at_end_vpos + dvpos,
bottom_vpos, delta, delta_bytes);
if (dy)
shift_glyph_matrix (w, current_matrix,
first_unchanged_at_end_vpos + dvpos,
bottom_vpos, dy);
if (first_unchanged_at_end_row)
first_unchanged_at_end_row += dvpos;
last_text_row_at_end = NULL;
if (dy < 0)
{
int last_vpos = XFASTINT (w->window_end_vpos) + dvpos;
struct glyph_row *last_row = MATRIX_ROW (current_matrix, last_vpos);
xassert (last_row->displays_text_p);
if (MATRIX_ROW_BOTTOM_Y (last_row) - dy >= it.last_visible_y)
{
init_to_row_start (&it, w, last_row);
it.vpos = last_vpos;
it.current_y = last_row->y;
}
else
{
init_to_row_end (&it, w, last_row);
it.vpos = 1 + last_vpos;
it.current_y = MATRIX_ROW_BOTTOM_Y (last_row);
++last_row;
}
it.continuation_lines_width = last_row->continuation_lines_width;
it.hpos = it.current_x = 0;
it.glyph_row = MATRIX_ROW (desired_matrix, it.vpos);
while (it.current_y < it.last_visible_y
&& !fonts_changed_p)
{
MATRIX_ROW (w->current_matrix, it.vpos)->enabled_p = 0;
if (display_line (&it))
last_text_row_at_end = it.glyph_row - 1;
}
}
if (first_unchanged_at_end_row
&& first_unchanged_at_end_row->y < it.last_visible_y
&& !last_text_row_at_end)
{
xassert (first_unchanged_at_end_row->displays_text_p);
row = find_last_row_displaying_text (w->current_matrix, &it,
first_unchanged_at_end_row);
xassert (row && MATRIX_ROW_DISPLAYS_TEXT_P (row));
w->window_end_pos = make_number (Z - MATRIX_ROW_END_CHARPOS (row));
w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
w->window_end_vpos
= make_number (MATRIX_ROW_VPOS (row, w->current_matrix));
xassert (w->window_end_bytepos >= 0);
IF_DEBUG (debug_method_add (w, "A"));
}
else if (last_text_row_at_end)
{
w->window_end_pos
= make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row_at_end));
w->window_end_bytepos
= Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row_at_end);
w->window_end_vpos
= make_number (MATRIX_ROW_VPOS (last_text_row_at_end, desired_matrix));
xassert (w->window_end_bytepos >= 0);
IF_DEBUG (debug_method_add (w, "B"));
}
else if (last_text_row)
{
w->window_end_pos
= make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row));
w->window_end_bytepos
= Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
w->window_end_vpos
= make_number (MATRIX_ROW_VPOS (last_text_row, desired_matrix));
xassert (w->window_end_bytepos >= 0);
}
else if (first_unchanged_at_end_row == NULL
&& last_text_row == NULL
&& last_text_row_at_end == NULL)
{
int first_vpos = WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0;
int vpos = XFASTINT (w->window_end_vpos);
struct glyph_row *current_row = current_matrix->rows + vpos;
struct glyph_row *desired_row = desired_matrix->rows + vpos;
for (row = NULL;
row == NULL && vpos >= first_vpos;
--vpos, --current_row, --desired_row)
{
if (desired_row->enabled_p)
{
if (desired_row->displays_text_p)
row = desired_row;
}
else if (current_row->displays_text_p)
row = current_row;
}
xassert (row != NULL);
w->window_end_vpos = make_number (vpos + 1);
w->window_end_pos = make_number (Z - MATRIX_ROW_END_CHARPOS (row));
w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
xassert (w->window_end_bytepos >= 0);
IF_DEBUG (debug_method_add (w, "C"));
}
else
abort ();
#if 0
enable_glyph_matrix_rows (current_matrix,
XFASTINT (w->window_end_vpos) + 1,
bottom_vpos, 0);
#endif
IF_DEBUG (debug_end_pos = XFASTINT (w->window_end_pos);
debug_end_vpos = XFASTINT (w->window_end_vpos));
w->window_end_valid = Qnil;
w->desired_matrix->no_scrolling_p = 1;
return 3;
#undef GIVE_UP
}
#if GLYPH_DEBUG
void dump_glyph_row P_ ((struct glyph_row *, int, int));
void dump_glyph_matrix P_ ((struct glyph_matrix *, int));
void dump_glyph P_ ((struct glyph_row *, struct glyph *, int));
void
dump_glyph_matrix (matrix, glyphs)
struct glyph_matrix *matrix;
int glyphs;
{
int i;
for (i = 0; i < matrix->nrows; ++i)
dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
}
void
dump_glyph (row, glyph, area)
struct glyph_row *row;
struct glyph *glyph;
int area;
{
if (glyph->type == CHAR_GLYPH)
{
fprintf (stderr,
" %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
glyph - row->glyphs[TEXT_AREA],
'C',
glyph->charpos,
(BUFFERP (glyph->object)
? 'B'
: (STRINGP (glyph->object)
? 'S'
: '-')),
glyph->pixel_width,
glyph->u.ch,
(glyph->u.ch < 0x80 && glyph->u.ch >= ' '
? glyph->u.ch
: '.'),
glyph->face_id,
glyph->left_box_line_p,
glyph->right_box_line_p);
}
else if (glyph->type == STRETCH_GLYPH)
{
fprintf (stderr,
" %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
glyph - row->glyphs[TEXT_AREA],
'S',
glyph->charpos,
(BUFFERP (glyph->object)
? 'B'
: (STRINGP (glyph->object)
? 'S'
: '-')),
glyph->pixel_width,
0,
'.',
glyph->face_id,
glyph->left_box_line_p,
glyph->right_box_line_p);
}
else if (glyph->type == IMAGE_GLYPH)
{
fprintf (stderr,
" %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
glyph - row->glyphs[TEXT_AREA],
'I',
glyph->charpos,
(BUFFERP (glyph->object)
? 'B'
: (STRINGP (glyph->object)
? 'S'
: '-')),
glyph->pixel_width,
glyph->u.img_id,
'.',
glyph->face_id,
glyph->left_box_line_p,
glyph->right_box_line_p);
}
}
void
dump_glyph_row (row, vpos, glyphs)
struct glyph_row *row;
int vpos, glyphs;
{
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, "%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%1.1d%1.1d %4d %4d %4d %4d %4d %4d %4d\n",
vpos,
MATRIX_ROW_START_CHARPOS (row),
MATRIX_ROW_END_CHARPOS (row),
row->used[TEXT_AREA],
row->contains_overlapping_glyphs_p,
row->enabled_p,
row->inverse_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,
row->ends_at_zv_p,
row->fill_line_p,
row->ends_in_middle_of_char_p,
row->starts_in_middle_of_char_p,
row->mouse_face_p,
row->x,
row->y,
row->pixel_width,
row->height,
row->visible_height,
row->ascent,
row->phys_ascent);
fprintf (stderr, "%9d %5d\t%5d\n", row->start.overlay_string_index,
row->end.overlay_string_index,
row->continuation_lines_width);
fprintf (stderr, "%9d %5d\n",
CHARPOS (row->start.string_pos),
CHARPOS (row->end.string_pos));
fprintf (stderr, "%9d %5d\n", row->start.dpvec_index,
row->end.dpvec_index);
}
if (glyphs > 1)
{
int area;
for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
{
struct glyph *glyph = row->glyphs[area];
struct glyph *glyph_end = glyph + row->used[area];
if (area == TEXT_AREA && glyph == glyph_end && glyph->charpos > 0)
++glyph_end;
if (glyph < glyph_end)
fprintf (stderr, " Glyph Type Pos O W Code C Face LR\n");
for (; glyph < glyph_end; ++glyph)
dump_glyph (row, glyph, area);
}
}
else if (glyphs == 1)
{
int area;
for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
{
char *s = (char *) alloca (row->used[area] + 1);
int i;
for (i = 0; i < row->used[area]; ++i)
{
struct glyph *glyph = row->glyphs[area] + i;
if (glyph->type == CHAR_GLYPH
&& glyph->u.ch < 0x80
&& glyph->u.ch >= ' ')
s[i] = glyph->u.ch;
else
s[i] = '.';
}
s[i] = '\0';
fprintf (stderr, "%3d: (%d) '%s'\n", vpos, row->enabled_p, s);
}
}
}
DEFUN ("dump-glyph-matrix", Fdump_glyph_matrix,
Sdump_glyph_matrix, 0, 1, "p",
"Dump the current matrix of the selected window to stderr.\n\
Shows contents of glyph row structures. With non-nil\n\
parameter GLYPHS, dump glyphs as well. If GLYPHS is 1 show\n\
glyphs in short form, otherwise show glyphs in long form.")
(glyphs)
Lisp_Object glyphs;
{
struct window *w = XWINDOW (selected_window);
struct buffer *buffer = XBUFFER (w->buffer);
fprintf (stderr, "PT = %d, BEGV = %d. ZV = %d\n",
BUF_PT (buffer), BUF_BEGV (buffer), BUF_ZV (buffer));
fprintf (stderr, "Cursor x = %d, y = %d, hpos = %d, vpos = %d\n",
w->cursor.x, w->cursor.y, w->cursor.hpos, w->cursor.vpos);
fprintf (stderr, "=============================================\n");
dump_glyph_matrix (w->current_matrix,
NILP (glyphs) ? 0 : XINT (glyphs));
return Qnil;
}
DEFUN ("dump-glyph-row", Fdump_glyph_row, Sdump_glyph_row, 1, 2, "",
"Dump glyph row ROW to stderr.\n\
GLYPH 0 means don't dump glyphs.\n\
GLYPH 1 means dump glyphs in short form.\n\
GLYPH > 1 or omitted means dump glyphs in long form.")
(row, glyphs)
Lisp_Object row, glyphs;
{
struct glyph_matrix *matrix;
int vpos;
CHECK_NUMBER (row, 0);
matrix = XWINDOW (selected_window)->current_matrix;
vpos = XINT (row);
if (vpos >= 0 && vpos < matrix->nrows)
dump_glyph_row (MATRIX_ROW (matrix, vpos),
vpos,
INTEGERP (glyphs) ? XINT (glyphs) : 2);
return Qnil;
}
DEFUN ("dump-tool-bar-row", Fdump_tool_bar_row, Sdump_tool_bar_row, 1, 2, "",
"Dump glyph row ROW of the tool-bar of the current frame to stderr.\n\
GLYPH 0 means don't dump glyphs.\n\
GLYPH 1 means dump glyphs in short form.\n\
GLYPH > 1 or omitted means dump glyphs in long form.")
(row, glyphs)
Lisp_Object row, glyphs;
{
struct frame *sf = SELECTED_FRAME ();
struct glyph_matrix *m = XWINDOW (sf->tool_bar_window)->current_matrix;
int vpos;
CHECK_NUMBER (row, 0);
vpos = XINT (row);
if (vpos >= 0 && vpos < m->nrows)
dump_glyph_row (MATRIX_ROW (m, vpos), vpos,
INTEGERP (glyphs) ? XINT (glyphs) : 2);
return Qnil;
}
DEFUN ("trace-redisplay", Ftrace_redisplay, Strace_redisplay, 0, 1, "P",
"Toggle tracing of redisplay.\n\
With ARG, turn tracing on if and only if ARG is positive.")
(arg)
Lisp_Object arg;
{
if (NILP (arg))
trace_redisplay_p = !trace_redisplay_p;
else
{
arg = Fprefix_numeric_value (arg);
trace_redisplay_p = XINT (arg) > 0;
}
return Qnil;
}
DEFUN ("trace-to-stderr", Ftrace_to_stderr, Strace_to_stderr, 1, MANY, "",
"Like `format', but print result to stderr.")
(nargs, args)
int nargs;
Lisp_Object *args;
{
Lisp_Object s = Fformat (nargs, args);
fprintf (stderr, "%s", XSTRING (s)->data);
return Qnil;
}
#endif
static struct glyph_row *
get_overlay_arrow_glyph_row (w)
struct window *w;
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
struct buffer *buffer = XBUFFER (w->buffer);
struct buffer *old = current_buffer;
unsigned char *arrow_string = XSTRING (Voverlay_arrow_string)->data;
int arrow_len = XSTRING (Voverlay_arrow_string)->size;
unsigned char *arrow_end = arrow_string + arrow_len;
unsigned char *p;
struct it it;
int multibyte_p;
int n_glyphs_before;
set_buffer_temp (buffer);
init_iterator (&it, w, -1, -1, &scratch_glyph_row, DEFAULT_FACE_ID);
it.glyph_row->used[TEXT_AREA] = 0;
SET_TEXT_POS (it.position, 0, 0);
multibyte_p = !NILP (buffer->enable_multibyte_characters);
p = arrow_string;
while (p < arrow_end)
{
Lisp_Object face, ilisp;
if (multibyte_p)
it.c = string_char_and_length (p, arrow_len, &it.len);
else
it.c = *p, it.len = 1;
p += it.len;
ilisp = make_number (p - arrow_string);
face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string);
it.face_id = compute_char_face (f, it.c, face);
n_glyphs_before = it.glyph_row->used[TEXT_AREA];
SET_TEXT_POS (it.position, -1, -1);
PRODUCE_GLYPHS (&it);
if (it.current_x > it.last_visible_x)
{
it.glyph_row->used[TEXT_AREA] = n_glyphs_before;
break;
}
}
set_buffer_temp (old);
return it.glyph_row;
}
static void
insert_left_trunc_glyphs (it)
struct it *it;
{
struct it truncate_it;
struct glyph *from, *end, *to, *toend;
xassert (!FRAME_WINDOW_P (it->f));
truncate_it = *it;
truncate_it.current_x = 0;
truncate_it.face_id = DEFAULT_FACE_ID;
truncate_it.glyph_row = &scratch_glyph_row;
truncate_it.glyph_row->used[TEXT_AREA] = 0;
CHARPOS (truncate_it.position) = BYTEPOS (truncate_it.position) = -1;
truncate_it.object = make_number (0);
produce_special_glyphs (&truncate_it, IT_TRUNCATION);
from = truncate_it.glyph_row->glyphs[TEXT_AREA];
end = from + truncate_it.glyph_row->used[TEXT_AREA];
to = it->glyph_row->glyphs[TEXT_AREA];
toend = to + it->glyph_row->used[TEXT_AREA];
while (from < end)
*to++ = *from++;
while (to < toend && CHAR_GLYPH_PADDING_P (*to))
{
from = truncate_it.glyph_row->glyphs[TEXT_AREA];
while (from < end)
*to++ = *from++;
}
if (to > toend)
it->glyph_row->used[TEXT_AREA] = to - it->glyph_row->glyphs[TEXT_AREA];
}
static void
compute_line_metrics (it)
struct it *it;
{
struct glyph_row *row = it->glyph_row;
int area, i;
if (FRAME_WINDOW_P (it->f))
{
int i, min_y, max_y;
if (row->height == 0)
{
if (it->max_ascent + it->max_descent == 0)
it->max_descent = it->max_phys_descent = CANON_Y_UNIT (it->f);
row->ascent = it->max_ascent;
row->height = it->max_ascent + it->max_descent;
row->phys_ascent = it->max_phys_ascent;
row->phys_height = it->max_phys_ascent + it->max_phys_descent;
}
row->pixel_width = row->x;
for (i = 0; i < row->used[TEXT_AREA]; ++i)
row->pixel_width += row->glyphs[TEXT_AREA][i].pixel_width;
xassert (row->pixel_width >= 0);
xassert (row->ascent >= 0 && row->height > 0);
row->overlapping_p = (MATRIX_ROW_OVERLAPS_SUCC_P (row)
|| MATRIX_ROW_OVERLAPS_PRED_P (row));
if (row == MATRIX_FIRST_TEXT_ROW (it->w->desired_matrix)
&& row->phys_ascent > row->ascent)
{
row->height += row->phys_ascent - row->ascent;
row->ascent = row->phys_ascent;
}
row->visible_height = row->height;
min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (it->w);
max_y = WINDOW_DISPLAY_HEIGHT_NO_MODE_LINE (it->w);
if (row->y < min_y)
row->visible_height -= min_y - row->y;
if (row->y + row->height > max_y)
row->visible_height -= row->y + row->height - max_y;
}
else
{
row->pixel_width = row->used[TEXT_AREA];
if (row->continued_p)
row->pixel_width -= it->continuation_pixel_width;
else if (row->truncated_on_right_p)
row->pixel_width -= it->truncation_pixel_width;
row->ascent = row->phys_ascent = 0;
row->height = row->phys_height = row->visible_height = 1;
}
row->hash = 0;
for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
for (i = 0; i < row->used[area]; ++i)
row->hash = ((((row->hash << 4) + (row->hash >> 24)) & 0x0fffffff)
+ row->glyphs[area][i].u.val
+ row->glyphs[area][i].face_id
+ row->glyphs[area][i].padding_p
+ (row->glyphs[area][i].type << 2));
it->max_ascent = it->max_descent = 0;
it->max_phys_ascent = it->max_phys_descent = 0;
}
static int
append_space (it, default_face_p)
struct it *it;
int default_face_p;
{
if (FRAME_WINDOW_P (it->f))
{
int n = it->glyph_row->used[TEXT_AREA];
if (it->glyph_row->glyphs[TEXT_AREA] + n
< it->glyph_row->glyphs[1 + TEXT_AREA])
{
enum display_element_type saved_what = it->what;
int saved_c = it->c, saved_len = it->len;
int saved_x = it->current_x;
int saved_face_id = it->face_id;
struct text_pos saved_pos;
Lisp_Object saved_object;
struct face *face;
saved_object = it->object;
saved_pos = it->position;
it->what = IT_CHARACTER;
bzero (&it->position, sizeof it->position);
it->object = make_number (0);
it->c = ' ';
it->len = 1;
if (default_face_p)
it->face_id = DEFAULT_FACE_ID;
else if (it->face_before_selective_p)
it->face_id = it->saved_face_id;
face = FACE_FROM_ID (it->f, it->face_id);
it->face_id = FACE_FOR_CHAR (it->f, face, 0);
PRODUCE_GLYPHS (it);
it->current_x = saved_x;
it->object = saved_object;
it->position = saved_pos;
it->what = saved_what;
it->face_id = saved_face_id;
it->len = saved_len;
it->c = saved_c;
return 1;
}
}
return 0;
}
static void
extend_face_to_end_of_line (it)
struct it *it;
{
struct face *face;
struct frame *f = it->f;
if (it->current_x >= it->last_visible_x)
return;
if (it->face_before_selective_p)
face = FACE_FROM_ID (it->f, it->saved_face_id);
else
face = FACE_FROM_ID (f, it->face_id);
if (FRAME_WINDOW_P (f)
&& face->box == FACE_NO_BOX
&& face->background == FRAME_BACKGROUND_PIXEL (f)
&& !face->stipple)
return;
it->glyph_row->fill_line_p = 1;
if (!SINGLE_BYTE_CHAR_P (it->c))
{
it->face_id = FACE_FOR_CHAR (f, face, 0);
}
if (FRAME_WINDOW_P (f))
{
if (it->glyph_row->used[TEXT_AREA] == 0)
{
it->glyph_row->glyphs[TEXT_AREA][0] = space_glyph;
it->glyph_row->glyphs[TEXT_AREA][0].face_id = it->face_id;
it->glyph_row->used[TEXT_AREA] = 1;
}
}
else
{
int saved_x = it->current_x;
struct text_pos saved_pos;
Lisp_Object saved_object;
enum display_element_type saved_what = it->what;
int saved_face_id = it->face_id;
saved_object = it->object;
saved_pos = it->position;
it->what = IT_CHARACTER;
bzero (&it->position, sizeof it->position);
it->object = make_number (0);
it->c = ' ';
it->len = 1;
it->face_id = face->id;
PRODUCE_GLYPHS (it);
while (it->current_x <= it->last_visible_x)
PRODUCE_GLYPHS (it);
it->current_x = saved_x;
it->object = saved_object;
it->position = saved_pos;
it->what = saved_what;
it->face_id = saved_face_id;
}
}
static int
trailing_whitespace_p (charpos)
int charpos;
{
int bytepos = CHAR_TO_BYTE (charpos);
int c = 0;
while (bytepos < ZV_BYTE
&& (c = FETCH_CHAR (bytepos),
c == ' ' || c == '\t'))
++bytepos;
if (bytepos >= ZV_BYTE || c == '\n' || c == '\r')
{
if (bytepos != PT_BYTE)
return 1;
}
return 0;
}
void
highlight_trailing_whitespace (f, row)
struct frame *f;
struct glyph_row *row;
{
int used = row->used[TEXT_AREA];
if (used)
{
struct glyph *start = row->glyphs[TEXT_AREA];
struct glyph *glyph = start + used - 1;
while (glyph >= start
&& glyph->type == CHAR_GLYPH
&& INTEGERP (glyph->object))
--glyph;
if (glyph >= start
&& BUFFERP (glyph->object)
&& (glyph->type == STRETCH_GLYPH
|| (glyph->type == CHAR_GLYPH
&& glyph->u.ch == ' '))
&& trailing_whitespace_p (glyph->charpos))
{
int face_id = lookup_named_face (f, Qtrailing_whitespace, 0);
while (glyph >= start
&& BUFFERP (glyph->object)
&& (glyph->type == STRETCH_GLYPH
|| (glyph->type == CHAR_GLYPH
&& glyph->u.ch == ' ')))
(glyph--)->face_id = face_id;
}
}
}
static int
cursor_row_p (w, row)
struct window *w;
struct glyph_row *row;
{
int cursor_row_p = 1;
if (PT == MATRIX_ROW_END_CHARPOS (row))
{
if (CHARPOS (row->end.string_pos) >= 0
|| MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
cursor_row_p = row->continued_p;
else if (row->ends_at_zv_p)
cursor_row_p = 1;
else
cursor_row_p = 0;
}
return cursor_row_p;
}
static int
display_line (it)
struct it *it;
{
struct glyph_row *row = it->glyph_row;
xassert (it->hpos == 0 && it->current_x == 0);
xassert (MATRIX_ROW_VPOS (row, it->w->desired_matrix)
< it->w->desired_matrix->nrows);
it->w->region_showing = it->region_beg_charpos > 0 ? Qt : Qnil;
prepare_desired_row (row);
row->y = it->current_y;
row->start = it->current;
row->continuation_lines_width = it->continuation_lines_width;
row->displays_text_p = 1;
row->starts_in_middle_of_char_p = it->starts_in_middle_of_char_p;
it->starts_in_middle_of_char_p = 0;
recenter_overlay_lists (current_buffer, IT_CHARPOS (*it));
if (it->current_x < it->first_visible_x)
move_it_in_display_line_to (it, ZV, it->first_visible_x,
MOVE_TO_POS | MOVE_TO_X);
row->ascent = it->max_ascent;
row->height = it->max_ascent + it->max_descent;
row->phys_ascent = it->max_phys_ascent;
row->phys_height = it->max_phys_ascent + it->max_phys_descent;
while (1)
{
int n_glyphs_before, hpos_before, x_before;
int x, i, nglyphs;
int ascent = 0, descent = 0, phys_ascent = 0, phys_descent = 0;
if (!get_next_display_element (it))
{
if ((append_space (it, 1) && row->used[TEXT_AREA] == 1)
|| row->used[TEXT_AREA] == 0)
{
row->glyphs[TEXT_AREA]->charpos = -1;
row->displays_text_p = 0;
if (!NILP (XBUFFER (it->w->buffer)->indicate_empty_lines)
&& (!MINI_WINDOW_P (it->w)
|| (minibuf_level && EQ (it->window, minibuf_window))))
row->indicate_empty_line_p = 1;
}
it->continuation_lines_width = 0;
row->ends_at_zv_p = 1;
break;
}
n_glyphs_before = row->used[TEXT_AREA];
x = it->current_x;
if (!it->truncate_lines_p)
{
ascent = it->max_ascent;
descent = it->max_descent;
phys_ascent = it->max_phys_ascent;
phys_descent = it->max_phys_descent;
}
PRODUCE_GLYPHS (it);
if (it->area != TEXT_AREA)
{
row->ascent = max (row->ascent, it->max_ascent);
row->height = max (row->height, it->max_ascent + it->max_descent);
row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent);
row->phys_height = max (row->phys_height,
it->max_phys_ascent + it->max_phys_descent);
set_iterator_to_next (it, 1);
continue;
}
nglyphs = row->used[TEXT_AREA] - n_glyphs_before;
hpos_before = it->hpos;
x_before = x;
if (
nglyphs > 0
&& it->current_x < it->last_visible_x)
{
it->hpos += nglyphs;
row->ascent = max (row->ascent, it->max_ascent);
row->height = max (row->height, it->max_ascent + it->max_descent);
row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent);
row->phys_height = max (row->phys_height,
it->max_phys_ascent + it->max_phys_descent);
if (it->current_x - it->pixel_width < it->first_visible_x)
row->x = x - it->first_visible_x;
}
else
{
int new_x;
struct glyph *glyph;
for (i = 0; i < nglyphs; ++i, x = new_x)
{
glyph = row->glyphs[TEXT_AREA] + n_glyphs_before + i;
new_x = x + glyph->pixel_width;
if (
!it->truncate_lines_p
&& (
new_x > it->last_visible_x
|| (new_x == it->last_visible_x
&& FRAME_WINDOW_P (it->f))))
{
if (it->hpos == 0
|| (new_x == it->last_visible_x
&& FRAME_WINDOW_P (it->f)))
{
row->continued_p = 1;
it->current_x = new_x;
it->continuation_lines_width += new_x;
++it->hpos;
if (i == nglyphs - 1)
set_iterator_to_next (it, 1);
}
else if (CHAR_GLYPH_PADDING_P (*glyph)
&& !FRAME_WINDOW_P (it->f))
{
row->used[TEXT_AREA] = n_glyphs_before;
while (row->glyphs[TEXT_AREA] + row->used[TEXT_AREA]
< row->glyphs[1 + TEXT_AREA])
produce_special_glyphs (it, IT_CONTINUATION);
row->continued_p = 1;
it->current_x = x_before;
it->continuation_lines_width += x_before;
it->max_ascent = ascent;
it->max_descent = descent;
it->max_phys_ascent = phys_ascent;
it->max_phys_descent = phys_descent;
}
else if (it->c == '\t' && FRAME_WINDOW_P (it->f))
{
it->continuation_lines_width += it->last_visible_x;
row->ends_in_middle_of_char_p = 1;
row->continued_p = 1;
glyph->pixel_width = it->last_visible_x - x;
it->starts_in_middle_of_char_p = 1;
}
else
{
row->used[TEXT_AREA] = n_glyphs_before + i;
if (!FRAME_WINDOW_P (it->f))
produce_special_glyphs (it, IT_CONTINUATION);
row->continued_p = 1;
it->continuation_lines_width += x;
if (nglyphs > 1 && i > 0)
{
row->ends_in_middle_of_char_p = 1;
it->starts_in_middle_of_char_p = 1;
}
it->max_ascent = ascent;
it->max_descent = descent;
it->max_phys_ascent = phys_ascent;
it->max_phys_descent = phys_descent;
}
break;
}
else if (new_x > it->first_visible_x)
{
++it->hpos;
if (x < it->first_visible_x)
row->x = x - it->first_visible_x;
}
else
{
abort ();
}
}
row->ascent = max (row->ascent, it->max_ascent);
row->height = max (row->height, it->max_ascent + it->max_descent);
row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent);
row->phys_height = max (row->phys_height,
it->max_phys_ascent + it->max_phys_descent);
if (row->continued_p)
break;
}
if (ITERATOR_AT_END_OF_LINE_P (it))
{
int used_before = row->used[TEXT_AREA];
row->ends_in_newline_from_string_p = STRINGP (it->object);
append_space (it, 0);
extend_face_to_end_of_line (it);
if (used_before == 0)
row->glyphs[TEXT_AREA]->charpos = CHARPOS (it->position);
set_iterator_to_next (it, 1);
it->continuation_lines_width = 0;
break;
}
set_iterator_to_next (it, 1);
if (it->truncate_lines_p
&& (FRAME_WINDOW_P (it->f)
? (it->current_x >= it->last_visible_x)
: (it->current_x > it->last_visible_x)))
{
if (!FRAME_WINDOW_P (it->f))
{
int i, n;
for (i = row->used[TEXT_AREA] - 1; i > 0; --i)
if (!CHAR_GLYPH_PADDING_P (row->glyphs[TEXT_AREA][i]))
break;
for (n = row->used[TEXT_AREA]; i < n; ++i)
{
row->used[TEXT_AREA] = i;
produce_special_glyphs (it, IT_TRUNCATION);
}
}
row->truncated_on_right_p = 1;
it->continuation_lines_width = 0;
reseat_at_next_visible_line_start (it, 0);
row->ends_at_zv_p = FETCH_BYTE (IT_BYTEPOS (*it) - 1) != '\n';
it->hpos = hpos_before;
it->current_x = x_before;
break;
}
}
if (it->first_visible_x
&& IT_CHARPOS (*it) != MATRIX_ROW_START_CHARPOS (row))
{
if (!FRAME_WINDOW_P (it->f))
insert_left_trunc_glyphs (it);
row->truncated_on_left_p = 1;
}
if (MARKERP (Voverlay_arrow_position)
&& current_buffer == XMARKER (Voverlay_arrow_position)->buffer
&& (MATRIX_ROW_START_CHARPOS (row)
== marker_position (Voverlay_arrow_position))
&& STRINGP (Voverlay_arrow_string)
&& ! overlay_arrow_seen)
{
if (!FRAME_WINDOW_P (it->f))
{
struct glyph_row *arrow_row = get_overlay_arrow_glyph_row (it->w);
struct glyph *glyph = arrow_row->glyphs[TEXT_AREA];
struct glyph *arrow_end = glyph + arrow_row->used[TEXT_AREA];
struct glyph *p = row->glyphs[TEXT_AREA];
struct glyph *p2, *end;
while (glyph < arrow_end)
*p++ = *glyph++;
p2 = p;
end = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
while (p2 < end && CHAR_GLYPH_PADDING_P (*p2))
++p2;
if (p2 > p)
{
while (p2 < end)
*p++ = *p2++;
row->used[TEXT_AREA] = p2 - row->glyphs[TEXT_AREA];
}
}
overlay_arrow_seen = 1;
row->overlay_arrow_p = 1;
}
compute_line_metrics (it);
row->end = it->current;
if (it->w->cursor.vpos < 0
&& PT >= MATRIX_ROW_START_CHARPOS (row)
&& PT <= MATRIX_ROW_END_CHARPOS (row)
&& cursor_row_p (it->w, row))
set_cursor_from_row (it->w, row, it->w->desired_matrix, 0, 0, 0, 0);
if (!NILP (Vshow_trailing_whitespace))
highlight_trailing_whitespace (it->f, it->glyph_row);
it->current_x = it->hpos = 0;
it->current_y += row->height;
++it->vpos;
++it->glyph_row;
return row->displays_text_p;
}
static void
display_menu_bar (w)
struct window *w;
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
struct it it;
Lisp_Object items;
int i;
#ifdef HAVE_NTGUI
if (!NILP (Vwindow_system))
return;
#endif
#ifdef USE_X_TOOLKIT
if (FRAME_X_P (f))
return;
#endif
#ifdef macintosh
if (FRAME_MAC_P (f))
return;
#endif
#ifdef USE_X_TOOLKIT
xassert (!FRAME_WINDOW_P (f));
init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID);
it.first_visible_x = 0;
it.last_visible_x = FRAME_WINDOW_WIDTH (f) * CANON_X_UNIT (f);
#else
if (FRAME_WINDOW_P (f))
{
struct window *menu_w;
xassert (WINDOWP (f->menu_bar_window));
menu_w = XWINDOW (f->menu_bar_window);
init_iterator (&it, menu_w, -1, -1, menu_w->desired_matrix->rows,
MENU_FACE_ID);
it.first_visible_x = 0;
it.last_visible_x = FRAME_WINDOW_WIDTH (f) * CANON_X_UNIT (f);
}
else
{
init_iterator (&it, w, -1, -1, f->desired_matrix->rows,
MENU_FACE_ID);
it.first_visible_x = 0;
it.last_visible_x = FRAME_WIDTH (f);
}
#endif
if (! mode_line_inverse_video)
it.base_face_id = it.face_id = DEFAULT_FACE_ID;
for (i = 0; i < FRAME_MENU_BAR_LINES (f); ++i)
{
struct glyph_row *row = it.glyph_row + i;
clear_glyph_row (row);
row->enabled_p = 1;
row->full_width_p = 1;
}
items = FRAME_MENU_BAR_ITEMS (it.f);
for (i = 0; i < XVECTOR (items)->size; i += 4)
{
Lisp_Object string;
string = AREF (items, i + 1);
if (NILP (string))
break;
AREF (items, i + 3) = make_number (it.hpos);
if (it.current_x < it.last_visible_x)
display_string (NULL, string, Qnil, 0, 0, &it,
XSTRING (string)->size + 1, 0, 0, -1);
}
if (it.current_x < it.last_visible_x)
display_string ("", Qnil, Qnil, 0, 0, &it, -1, 0, 0, -1);
compute_line_metrics (&it);
}
static int
redisplay_mode_lines (window, force)
Lisp_Object window;
int force;
{
int nwindows = 0;
while (!NILP (window))
{
struct window *w = XWINDOW (window);
if (WINDOWP (w->hchild))
nwindows += redisplay_mode_lines (w->hchild, force);
else if (WINDOWP (w->vchild))
nwindows += redisplay_mode_lines (w->vchild, force);
else if (force
|| FRAME_GARBAGED_P (XFRAME (w->frame))
|| !MATRIX_MODE_LINE_ROW (w->current_matrix)->enabled_p)
{
struct text_pos lpoint;
struct buffer *old = current_buffer;
SET_TEXT_POS (lpoint, PT, PT_BYTE);
set_buffer_internal_1 (XBUFFER (w->buffer));
if (!EQ (window, selected_window))
{
struct text_pos pt;
SET_TEXT_POS_FROM_MARKER (pt, w->pointm);
if (CHARPOS (pt) < BEGV)
TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
else if (CHARPOS (pt) > (ZV - 1))
TEMP_SET_PT_BOTH (ZV, ZV_BYTE);
else
TEMP_SET_PT_BOTH (CHARPOS (pt), BYTEPOS (pt));
}
clear_glyph_matrix (w->desired_matrix);
if (display_mode_lines (w))
{
++nwindows;
w->must_be_updated_p = 1;
}
set_buffer_internal_1 (old);
TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
}
window = w->next;
}
return nwindows;
}
static int
display_mode_lines (w)
struct window *w;
{
Lisp_Object old_selected_window, old_selected_frame;
int n = 0;
old_selected_frame = selected_frame;
selected_frame = w->frame;
old_selected_window = selected_window;
XSETWINDOW (selected_window, w);
line_number_displayed = 0;
w->column_number_displayed = Qnil;
if (WINDOW_WANTS_MODELINE_P (w))
{
display_mode_line (w, MODE_LINE_FACE_ID,
current_buffer->mode_line_format);
++n;
}
if (WINDOW_WANTS_HEADER_LINE_P (w))
{
display_mode_line (w, HEADER_LINE_FACE_ID,
current_buffer->header_line_format);
++n;
}
selected_frame = old_selected_frame;
selected_window = old_selected_window;
return n;
}
static int
display_mode_line (w, face_id, format)
struct window *w;
enum face_id face_id;
Lisp_Object format;
{
struct it it;
struct face *face;
init_iterator (&it, w, -1, -1, NULL, face_id);
prepare_desired_row (it.glyph_row);
if (! mode_line_inverse_video)
it.base_face_id = it.face_id = DEFAULT_FACE_ID;
push_frame_kboard (it.f);
display_mode_element (&it, 0, 0, 0, format);
pop_frame_kboard ();
display_string (" ", Qnil, Qnil, 0, 0, &it, 10000, -1, -1, 0);
compute_line_metrics (&it);
it.glyph_row->full_width_p = 1;
it.glyph_row->mode_line_p = 1;
it.glyph_row->inverse_p = 0;
it.glyph_row->continued_p = 0;
it.glyph_row->truncated_on_left_p = 0;
it.glyph_row->truncated_on_right_p = 0;
face = FACE_FROM_ID (it.f, face_id);
extend_face_to_end_of_line (&it);
if (face->box != FACE_NO_BOX)
{
struct glyph *last = (it.glyph_row->glyphs[TEXT_AREA]
+ it.glyph_row->used[TEXT_AREA] - 1);
last->right_box_line_p = 1;
}
return it.glyph_row->height;
}
static int
display_mode_element (it, depth, field_width, precision, elt)
struct it *it;
int depth;
int field_width, precision;
Lisp_Object elt;
{
int n = 0, field, prec;
tail_recurse:
if (depth > 10)
goto invalid;
depth++;
switch (SWITCH_ENUM_CAST (XTYPE (elt)))
{
case Lisp_String:
{
unsigned char c;
unsigned char *this = XSTRING (elt)->data;
unsigned char *lisp_string = this;
while ((precision <= 0 || n < precision)
&& *this
&& (frame_title_ptr
|| it->current_x < it->last_visible_x))
{
unsigned char *last = this;
while ((c = *this++) != '\0' && c != '%')
;
if (this - 1 != last)
{
--this;
prec = chars_in_text (last, this - last);
if (precision > 0 && prec > precision - n)
prec = precision - n;
if (frame_title_ptr)
n += store_frame_title (last, 0, prec);
else
{
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));
}
}
else
{
unsigned char *percent_position = this;
field = 0;
while ((c = *this++) >= '0' && c <= '9')
field = field * 10 + c - '0';
if (field_width - n > 0 && field > field_width - n)
field = field_width - n;
prec = precision - n;
if (c == 'M')
n += display_mode_element (it, depth, field, prec,
Vglobal_mode_string);
else if (c != 0)
{
int multibyte;
unsigned char *spec
= decode_mode_spec (it->w, c, field, prec, &multibyte);
if (frame_title_ptr)
n += store_frame_title (spec, field, prec);
else
{
int nglyphs_before, bytepos, charpos, nwritten;
nglyphs_before = it->glyph_row->used[TEXT_AREA];
bytepos = percent_position - XSTRING (elt)->data;
charpos = (STRING_MULTIBYTE (elt)
? string_byte_to_char (elt, bytepos)
: bytepos);
nwritten = display_string (spec, Qnil, elt,
charpos, 0, it,
field, prec, 0,
multibyte);
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;
}
}
}
else
break;
}
}
}
break;
case Lisp_Symbol:
{
register Lisp_Object tem;
tem = Fboundp (elt);
if (!NILP (tem))
{
tem = Fsymbol_value (elt);
if (STRINGP (tem))
{
prec = precision - n;
if (frame_title_ptr)
n += store_frame_title (XSTRING (tem)->data, -1, prec);
else
n += display_string (NULL, tem, Qnil, 0, 0, it,
0, prec, 0, STRING_MULTIBYTE (tem));
}
else if (!EQ (tem, elt))
{
elt = tem;
goto tail_recurse;
}
}
}
break;
case Lisp_Cons:
{
register Lisp_Object car, tem;
car = XCAR (elt);
if (EQ (car, QCeval) && CONSP (XCDR (elt)))
{
struct gcpro gcpro1;
Lisp_Object spec;
spec = safe_eval (XCAR (XCDR (elt)));
GCPRO1 (spec);
n += display_mode_element (it, depth, field_width - n,
precision - n, spec);
UNGCPRO;
}
else if (SYMBOLP (car))
{
tem = Fboundp (car);
elt = XCDR (elt);
if (!CONSP (elt))
goto invalid;
if (!NILP (tem))
{
tem = Fsymbol_value (car);
if (!NILP (tem))
{
elt = XCAR (elt);
goto tail_recurse;
}
}
elt = XCDR (elt);
if (NILP (elt))
break;
else if (!CONSP (elt))
goto invalid;
elt = XCAR (elt);
goto tail_recurse;
}
else if (INTEGERP (car))
{
register int lim = XINT (car);
elt = XCDR (elt);
if (lim < 0)
{
if (precision <= 0)
precision = -lim;
else
precision = min (precision, -lim);
}
else if (lim > 0)
{
if (precision > 0)
lim = min (precision, lim);
field_width = max (lim, field_width);
}
goto tail_recurse;
}
else if (STRINGP (car) || CONSP (car))
{
register int limit = 50;
while (CONSP (elt)
&& --limit > 0
&& (precision <= 0 || n < precision))
{
n += display_mode_element (it, depth, field_width - n,
precision - n, XCAR (elt));
elt = XCDR (elt);
}
}
}
break;
default:
invalid:
if (frame_title_ptr)
n += store_frame_title ("*invalid*", 0, precision - n);
else
n += display_string ("*invalid*", Qnil, Qnil, 0, 0, it, 0,
precision - n, 0, 0);
return n;
}
if (field_width > 0 && n < field_width)
{
if (frame_title_ptr)
n += store_frame_title ("", field_width - n, 0);
else
n += display_string ("", Qnil, Qnil, 0, 0, it, field_width - n,
0, 0, 0);
}
return n;
}
static void
pint2str (buf, width, d)
register char *buf;
register int width;
register int d;
{
register char *p = buf;
if (d <= 0)
*p++ = '0';
else
{
while (d > 0)
{
*p++ = d % 10 + '0';
d /= 10;
}
}
for (width -= (int) (p - buf); width > 0; --width)
*p++ = ' ';
*p-- = '\0';
while (p > buf)
{
d = *buf;
*buf++ = *p;
*p-- = d;
}
}
static unsigned char invalid_eol_type[] = "(*invalid*)";
static char *
decode_mode_spec_coding (coding_system, buf, eol_flag)
Lisp_Object coding_system;
register char *buf;
int eol_flag;
{
Lisp_Object val;
int multibyte = !NILP (current_buffer->enable_multibyte_characters);
unsigned char *eol_str;
int eol_str_len;
Lisp_Object eoltype;
val = Fget (coding_system, Qcoding_system);
eoltype = Qnil;
if (!VECTORP (val))
{
if (multibyte)
*buf++ = '-';
if (eol_flag)
eoltype = eol_mnemonic_undecided;
}
else
{
Lisp_Object eolvalue;
eolvalue = Fget (coding_system, Qeol_type);
if (multibyte)
*buf++ = XFASTINT (AREF (val, 1));
if (eol_flag)
{
if (NILP (eolvalue))
eoltype = eol_mnemonic_undecided;
else if (VECTORP (eolvalue))
eoltype = eol_mnemonic_undecided;
else
eoltype = (XFASTINT (eolvalue) == 0
? eol_mnemonic_unix
: (XFASTINT (eolvalue) == 1
? eol_mnemonic_dos : eol_mnemonic_mac));
}
}
if (eol_flag)
{
if (STRINGP (eoltype))
{
eol_str = XSTRING (eoltype)->data;
eol_str_len = XSTRING (eoltype)->size;
}
else if (INTEGERP (eoltype)
&& CHAR_VALID_P (XINT (eoltype), 0))
{
eol_str = (unsigned char *) alloca (MAX_MULTIBYTE_LENGTH);
eol_str_len = CHAR_STRING (XINT (eoltype), eol_str);
}
else
{
eol_str = invalid_eol_type;
eol_str_len = sizeof (invalid_eol_type) - 1;
}
bcopy (eol_str, buf, eol_str_len);
buf += eol_str_len;
}
return buf;
}
static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
static char *
decode_mode_spec (w, c, field_width, precision, multibyte)
struct window *w;
register int c;
int field_width, precision;
int *multibyte;
{
Lisp_Object obj;
struct frame *f = XFRAME (WINDOW_FRAME (w));
char *decode_mode_spec_buf = f->decode_mode_spec_buffer;
struct buffer *b = XBUFFER (w->buffer);
obj = Qnil;
*multibyte = 0;
switch (c)
{
case '*':
if (!NILP (b->read_only))
return "%";
if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
return "*";
return "-";
case '+':
if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
return "*";
if (!NILP (b->read_only))
return "%";
return "-";
case '&':
if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
return "*";
return "-";
case '%':
return "%";
case '[':
{
int i;
char *p;
if (command_loop_level > 5)
return "[[[... ";
p = decode_mode_spec_buf;
for (i = 0; i < command_loop_level; i++)
*p++ = '[';
*p = 0;
return decode_mode_spec_buf;
}
case ']':
{
int i;
char *p;
if (command_loop_level > 5)
return " ...]]]";
p = decode_mode_spec_buf;
for (i = 0; i < command_loop_level; i++)
*p++ = ']';
*p = 0;
return decode_mode_spec_buf;
}
case '-':
{
register int i;
if (field_width <= 0
|| field_width > sizeof (lots_of_dashes))
{
for (i = 0; i < FRAME_MESSAGE_BUF_SIZE (f) - 1; ++i)
decode_mode_spec_buf[i] = '-';
decode_mode_spec_buf[i] = '\0';
return decode_mode_spec_buf;
}
else
return lots_of_dashes;
}
case 'b':
obj = b->name;
break;
case 'c':
{
int col = current_column ();
w->column_number_displayed = make_number (col);
pint2str (decode_mode_spec_buf, field_width, col);
return decode_mode_spec_buf;
}
case 'F':
if (!NILP (f->title))
return (char *) XSTRING (f->title)->data;
if (f->explicit_name || ! FRAME_WINDOW_P (f))
return (char *) XSTRING (f->name)->data;
return "Emacs";
case 'f':
obj = b->filename;
break;
case 'l':
{
int startpos = XMARKER (w->start)->charpos;
int startpos_byte = marker_byte_position (w->start);
int line, linepos, linepos_byte, topline;
int nlines, junk;
int height = XFASTINT (w->height);
if (EQ (w->base_line_pos, w->buffer))
goto no_value;
else if (BUFFERP (w->base_line_pos))
w->base_line_pos = Qnil;
if (INTEGERP (Vline_number_display_limit)
&& BUF_ZV (b) - BUF_BEGV (b) > XINT (Vline_number_display_limit))
{
w->base_line_pos = Qnil;
w->base_line_number = Qnil;
goto no_value;
}
if (!NILP (w->base_line_number)
&& !NILP (w->base_line_pos)
&& XFASTINT (w->base_line_pos) <= startpos)
{
line = XFASTINT (w->base_line_number);
linepos = XFASTINT (w->base_line_pos);
linepos_byte = buf_charpos_to_bytepos (b, linepos);
}
else
{
line = 1;
linepos = BUF_BEGV (b);
linepos_byte = BUF_BEGV_BYTE (b);
}
nlines = display_count_lines (linepos, linepos_byte,
startpos_byte,
startpos, &junk);
topline = nlines + line;
if (startpos == BUF_BEGV (b))
{
w->base_line_number = make_number (topline);
w->base_line_pos = make_number (BUF_BEGV (b));
}
else if (nlines < height + 25 || nlines > height * 3 + 50
|| linepos == BUF_BEGV (b))
{
int limit = BUF_BEGV (b);
int limit_byte = BUF_BEGV_BYTE (b);
int position;
int distance = (height * 2 + 30) * line_number_display_limit_width;
if (startpos - distance > limit)
{
limit = startpos - distance;
limit_byte = CHAR_TO_BYTE (limit);
}
nlines = display_count_lines (startpos, startpos_byte,
limit_byte,
- (height * 2 + 30),
&position);
if (position == limit_byte && limit == startpos - distance)
{
w->base_line_pos = w->buffer;
w->base_line_number = Qnil;
goto no_value;
}
w->base_line_number = make_number (topline - nlines);
w->base_line_pos = make_number (BYTE_TO_CHAR (position));
}
nlines = display_count_lines (startpos, startpos_byte,
PT_BYTE, PT, &junk);
line_number_displayed = 1;
pint2str (decode_mode_spec_buf, field_width, topline + nlines);
return decode_mode_spec_buf;
no_value:
{
char* p = decode_mode_spec_buf;
int pad = field_width - 2;
while (pad-- > 0)
*p++ = ' ';
*p++ = '?';
*p++ = '?';
*p = '\0';
return decode_mode_spec_buf;
}
}
break;
case 'm':
obj = b->mode_name;
break;
case 'n':
if (BUF_BEGV (b) > BUF_BEG (b) || BUF_ZV (b) < BUF_Z (b))
return " Narrow";
break;
case 'p':
{
int pos = marker_position (w->start);
int total = BUF_ZV (b) - BUF_BEGV (b);
if (XFASTINT (w->window_end_pos) <= BUF_Z (b) - BUF_ZV (b))
{
if (pos <= BUF_BEGV (b))
return "All";
else
return "Bottom";
}
else if (pos <= BUF_BEGV (b))
return "Top";
else
{
if (total > 1000000)
total = ((pos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100);
else
total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total;
if (total == 100)
total = 99;
sprintf (decode_mode_spec_buf, "%2d%%", total);
return decode_mode_spec_buf;
}
}
case 'P':
{
int toppos = marker_position (w->start);
int botpos = BUF_Z (b) - XFASTINT (w->window_end_pos);
int total = BUF_ZV (b) - BUF_BEGV (b);
if (botpos >= BUF_ZV (b))
{
if (toppos <= BUF_BEGV (b))
return "All";
else
return "Bottom";
}
else
{
if (total > 1000000)
total = ((botpos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100);
else
total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total;
if (total == 100)
total = 99;
if (toppos <= BUF_BEGV (b))
sprintf (decode_mode_spec_buf, "Top%2d%%", total);
else
sprintf (decode_mode_spec_buf, "%2d%%", total);
return decode_mode_spec_buf;
}
}
case 's':
obj = Fget_buffer_process (w->buffer);
if (NILP (obj))
return "no process";
#ifdef subprocesses
obj = Fsymbol_name (Fprocess_status (obj));
#endif
break;
case 't':
#ifdef MODE_LINE_BINARY_TEXT
return MODE_LINE_BINARY_TEXT (b);
#else
return "T";
#endif
case 'z':
case 'Z':
{
int eol_flag = (c == 'Z');
char *p = decode_mode_spec_buf;
if (! FRAME_WINDOW_P (f))
{
p = decode_mode_spec_coding (keyboard_coding.symbol, p, 0);
p = decode_mode_spec_coding (terminal_coding.symbol, p, 0);
}
p = decode_mode_spec_coding (b->buffer_file_coding_system,
p, eol_flag);
#if 0
#ifdef subprocesses
obj = Fget_buffer_process (Fcurrent_buffer ());
if (PROCESSP (obj))
{
p = decode_mode_spec_coding (XPROCESS (obj)->decode_coding_system,
p, eol_flag);
p = decode_mode_spec_coding (XPROCESS (obj)->encode_coding_system,
p, eol_flag);
}
#endif
#endif
*p = 0;
return decode_mode_spec_buf;
}
}
if (STRINGP (obj))
{
*multibyte = STRING_MULTIBYTE (obj);
return (char *) XSTRING (obj)->data;
}
else
return "";
}
static int
display_count_lines (start, start_byte, limit_byte, count, byte_pos_ptr)
int start, start_byte, limit_byte, count;
int *byte_pos_ptr;
{
register unsigned char *cursor;
unsigned char *base;
register int ceiling;
register unsigned char *ceiling_addr;
int orig_count = count;
int selective_display = (!NILP (current_buffer->selective_display)
&& !INTEGERP (current_buffer->selective_display));
if (count > 0)
{
while (start_byte < limit_byte)
{
ceiling = BUFFER_CEILING_OF (start_byte);
ceiling = min (limit_byte - 1, ceiling);
ceiling_addr = BYTE_POS_ADDR (ceiling) + 1;
base = (cursor = BYTE_POS_ADDR (start_byte));
while (1)
{
if (selective_display)
while (*cursor != '\n' && *cursor != 015 && ++cursor != ceiling_addr)
;
else
while (*cursor != '\n' && ++cursor != ceiling_addr)
;
if (cursor != ceiling_addr)
{
if (--count == 0)
{
start_byte += cursor - base + 1;
*byte_pos_ptr = start_byte;
return orig_count;
}
else
if (++cursor == ceiling_addr)
break;
}
else
break;
}
start_byte += cursor - base;
}
}
else
{
while (start_byte > limit_byte)
{
ceiling = BUFFER_FLOOR_OF (start_byte - 1);
ceiling = max (limit_byte, ceiling);
ceiling_addr = BYTE_POS_ADDR (ceiling) - 1;
base = (cursor = BYTE_POS_ADDR (start_byte - 1) + 1);
while (1)
{
if (selective_display)
while (--cursor != ceiling_addr
&& *cursor != '\n' && *cursor != 015)
;
else
while (--cursor != ceiling_addr && *cursor != '\n')
;
if (cursor != ceiling_addr)
{
if (++count == 0)
{
start_byte += cursor - base + 1;
*byte_pos_ptr = start_byte;
return - orig_count - 1;
}
}
else
break;
}
start_byte += cursor - base + 1;
}
}
*byte_pos_ptr = limit_byte;
if (count < 0)
return - orig_count + count;
return orig_count - count;
}
static int
display_string (string, lisp_string, face_string, face_string_pos,
start, it, field_width, precision, max_x, multibyte)
unsigned char *string;
Lisp_Object lisp_string;
Lisp_Object face_string;
int face_string_pos;
int start;
struct it *it;
int field_width, precision, max_x;
int multibyte;
{
int hpos_at_start = it->hpos;
int saved_face_id = it->face_id;
struct glyph_row *row = it->glyph_row;
reseat_to_string (it, string, lisp_string, start,
precision, field_width, multibyte);
if (STRINGP (face_string))
{
int endptr;
struct face *face;
it->face_id
= face_at_string_position (it->w, face_string, face_string_pos,
0, it->region_beg_charpos,
it->region_end_charpos,
&endptr, it->base_face_id, 0);
face = FACE_FROM_ID (it->f, it->face_id);
it->face_box_p = face->box != FACE_NO_BOX;
}
if (max_x <= 0)
max_x = it->last_visible_x;
else
max_x = min (max_x, it->last_visible_x);
if (it->current_x < it->first_visible_x)
move_it_in_display_line_to (it, 100000, it->first_visible_x,
MOVE_TO_POS | MOVE_TO_X);
row->ascent = it->max_ascent;
row->height = it->max_ascent + it->max_descent;
row->phys_ascent = it->max_phys_ascent;
row->phys_height = it->max_phys_ascent + it->max_phys_descent;
while (it->current_x < max_x)
{
int x_before, x, n_glyphs_before, i, nglyphs;
if (!get_next_display_element (it))
break;
x_before = it->current_x;
n_glyphs_before = it->glyph_row->used[TEXT_AREA];
PRODUCE_GLYPHS (it);
nglyphs = it->glyph_row->used[TEXT_AREA] - n_glyphs_before;
i = 0;
x = x_before;
while (i < nglyphs)
{
struct glyph *glyph = row->glyphs[TEXT_AREA] + n_glyphs_before + i;
if (!it->truncate_lines_p
&& x + glyph->pixel_width > max_x)
{
if (CHAR_GLYPH_PADDING_P (*glyph))
{
it->glyph_row->used[TEXT_AREA] = n_glyphs_before;
it->current_x = x_before;
}
else
{
it->glyph_row->used[TEXT_AREA] = n_glyphs_before + i;
it->current_x = x;
}
break;
}
else if (x + glyph->pixel_width > it->first_visible_x)
{
++it->hpos;
if (x < it->first_visible_x)
it->glyph_row->x = x - it->first_visible_x;
}
else
{
abort ();
}
row->ascent = max (row->ascent, it->max_ascent);
row->height = max (row->height, it->max_ascent + it->max_descent);
row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent);
row->phys_height = max (row->phys_height,
it->max_phys_ascent + it->max_phys_descent);
x += glyph->pixel_width;
++i;
}
if (i < nglyphs)
break;
if (ITERATOR_AT_END_OF_LINE_P (it))
{
it->continuation_lines_width = 0;
break;
}
set_iterator_to_next (it, 1);
if (it->truncate_lines_p
&& it->current_x >= it->last_visible_x)
{
if (IT_CHARPOS (*it) < it->string_nchars)
{
if (!FRAME_WINDOW_P (it->f))
{
int i, n;
if (it->current_x > it->last_visible_x)
{
for (i = row->used[TEXT_AREA] - 1; i > 0; --i)
if (!CHAR_GLYPH_PADDING_P (row->glyphs[TEXT_AREA][i]))
break;
for (n = row->used[TEXT_AREA]; i < n; ++i)
{
row->used[TEXT_AREA] = i;
produce_special_glyphs (it, IT_TRUNCATION);
}
}
produce_special_glyphs (it, IT_TRUNCATION);
}
it->glyph_row->truncated_on_right_p = 1;
}
break;
}
}
if (it->first_visible_x
&& IT_CHARPOS (*it) > 0)
{
if (!FRAME_WINDOW_P (it->f))
insert_left_trunc_glyphs (it);
it->glyph_row->truncated_on_left_p = 1;
}
it->face_id = saved_face_id;
return it->hpos - hpos_at_start;
}
int
invisible_p (propval, list)
register Lisp_Object propval;
Lisp_Object list;
{
register Lisp_Object tail, proptail;
for (tail = list; CONSP (tail); tail = XCDR (tail))
{
register Lisp_Object tem;
tem = XCAR (tail);
if (EQ (propval, tem))
return 1;
if (CONSP (tem) && EQ (propval, XCAR (tem)))
return 1;
}
if (CONSP (propval))
{
for (proptail = propval; CONSP (proptail); proptail = XCDR (proptail))
{
Lisp_Object propelt;
propelt = XCAR (proptail);
for (tail = list; CONSP (tail); tail = XCDR (tail))
{
register Lisp_Object tem;
tem = XCAR (tail);
if (EQ (propelt, tem))
return 1;
if (CONSP (tem) && EQ (propelt, XCAR (tem)))
return 1;
}
}
}
return 0;
}
int
invisible_ellipsis_p (propval, list)
register Lisp_Object propval;
Lisp_Object list;
{
register Lisp_Object tail, proptail;
for (tail = list; CONSP (tail); tail = XCDR (tail))
{
register Lisp_Object tem;
tem = XCAR (tail);
if (CONSP (tem) && EQ (propval, XCAR (tem)))
return ! NILP (XCDR (tem));
}
if (CONSP (propval))
for (proptail = propval; CONSP (proptail); proptail = XCDR (proptail))
{
Lisp_Object propelt;
propelt = XCAR (proptail);
for (tail = list; CONSP (tail); tail = XCDR (tail))
{
register Lisp_Object tem;
tem = XCAR (tail);
if (CONSP (tem) && EQ (propelt, XCAR (tem)))
return ! NILP (XCDR (tem));
}
}
return 0;
}
void
syms_of_xdisp ()
{
Vwith_echo_area_save_vector = Qnil;
staticpro (&Vwith_echo_area_save_vector);
Vmessage_stack = Qnil;
staticpro (&Vmessage_stack);
Qinhibit_redisplay = intern ("inhibit-redisplay");
staticpro (&Qinhibit_redisplay);
#if GLYPH_DEBUG
defsubr (&Sdump_glyph_matrix);
defsubr (&Sdump_glyph_row);
defsubr (&Sdump_tool_bar_row);
defsubr (&Strace_redisplay);
defsubr (&Strace_to_stderr);
#endif
#ifdef HAVE_WINDOW_SYSTEM
defsubr (&Stool_bar_lines_needed);
#endif
staticpro (&Qmenu_bar_update_hook);
Qmenu_bar_update_hook = intern ("menu-bar-update-hook");
staticpro (&Qoverriding_terminal_local_map);
Qoverriding_terminal_local_map = intern ("overriding-terminal-local-map");
staticpro (&Qoverriding_local_map);
Qoverriding_local_map = intern ("overriding-local-map");
staticpro (&Qwindow_scroll_functions);
Qwindow_scroll_functions = intern ("window-scroll-functions");
staticpro (&Qredisplay_end_trigger_functions);
Qredisplay_end_trigger_functions = intern ("redisplay-end-trigger-functions");
staticpro (&Qinhibit_point_motion_hooks);
Qinhibit_point_motion_hooks = intern ("inhibit-point-motion-hooks");
QCdata = intern (":data");
staticpro (&QCdata);
Qdisplay = intern ("display");
staticpro (&Qdisplay);
Qspace_width = intern ("space-width");
staticpro (&Qspace_width);
Qraise = intern ("raise");
staticpro (&Qraise);
Qspace = intern ("space");
staticpro (&Qspace);
Qmargin = intern ("margin");
staticpro (&Qmargin);
Qleft_margin = intern ("left-margin");
staticpro (&Qleft_margin);
Qright_margin = intern ("right-margin");
staticpro (&Qright_margin);
Qalign_to = intern ("align-to");
staticpro (&Qalign_to);
QCalign_to = intern (":align-to");
staticpro (&QCalign_to);
Qrelative_width = intern ("relative-width");
staticpro (&Qrelative_width);
QCrelative_width = intern (":relative-width");
staticpro (&QCrelative_width);
QCrelative_height = intern (":relative-height");
staticpro (&QCrelative_height);
QCeval = intern (":eval");
staticpro (&QCeval);
Qwhen = intern ("when");
staticpro (&Qwhen);
QCfile = intern (":file");
staticpro (&QCfile);
Qfontified = intern ("fontified");
staticpro (&Qfontified);
Qfontification_functions = intern ("fontification-functions");
staticpro (&Qfontification_functions);
Qtrailing_whitespace = intern ("trailing-whitespace");
staticpro (&Qtrailing_whitespace);
Qimage = intern ("image");
staticpro (&Qimage);
Qmessage_truncate_lines = intern ("message-truncate-lines");
staticpro (&Qmessage_truncate_lines);
Qgrow_only = intern ("grow-only");
staticpro (&Qgrow_only);
Qinhibit_menubar_update = intern ("inhibit-menubar-update");
staticpro (&Qinhibit_menubar_update);
Qinhibit_eval_during_redisplay = intern ("inhibit-eval-during-redisplay");
staticpro (&Qinhibit_eval_during_redisplay);
Qposition = intern ("position");
staticpro (&Qposition);
Qbuffer_position = intern ("buffer-position");
staticpro (&Qbuffer_position);
Qobject = intern ("object");
staticpro (&Qobject);
last_arrow_position = Qnil;
last_arrow_string = Qnil;
staticpro (&last_arrow_position);
staticpro (&last_arrow_string);
echo_buffer[0] = echo_buffer[1] = Qnil;
staticpro (&echo_buffer[0]);
staticpro (&echo_buffer[1]);
echo_area_buffer[0] = echo_area_buffer[1] = Qnil;
staticpro (&echo_area_buffer[0]);
staticpro (&echo_area_buffer[1]);
Vmessages_buffer_name = build_string ("*Messages*");
staticpro (&Vmessages_buffer_name);
DEFVAR_LISP ("show-trailing-whitespace", &Vshow_trailing_whitespace,
"Non-nil means highlight trailing whitespace.\n\
The face used for trailing whitespace is `trailing-whitespace'.");
Vshow_trailing_whitespace = Qnil;
DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay,
"Non-nil means don't actually do any redisplay.\n\
This is used for internal purposes.");
Vinhibit_redisplay = Qnil;
DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
"String (or mode line construct) included (normally) in `mode-line-format'.");
Vglobal_mode_string = Qnil;
DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
"Marker for where to display an arrow on top of the buffer text.\n\
This must be the beginning of a line in order to work.\n\
See also `overlay-arrow-string'.");
Voverlay_arrow_position = Qnil;
DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
"String to display as an arrow. See also `overlay-arrow-position'.");
Voverlay_arrow_string = Qnil;
DEFVAR_INT ("scroll-step", &scroll_step,
"*The number of lines to try scrolling a window by when point moves out.\n\
If that fails to bring point back on frame, point is centered instead.\n\
If this is zero, point is always centered after it moves off frame.\n\
If you want scrolling to always be a line at a time, you should set\n\
`scroll-conservatively' to a large value rather than set this to 1.");
DEFVAR_INT ("scroll-conservatively", &scroll_conservatively,
"*Scroll up to this many lines, to bring point back on screen.\n\
A value of zero means to scroll the text to center point vertically\n\
in the window.");
scroll_conservatively = 0;
DEFVAR_INT ("scroll-margin", &scroll_margin,
"*Number of lines of margin at the top and bottom of a window.\n\
Recenter the window whenever point gets within this many lines\n\
of the top or bottom of the window.");
scroll_margin = 0;
#if GLYPH_DEBUG
DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
#endif
DEFVAR_BOOL ("truncate-partial-width-windows",
&truncate_partial_width_windows,
"*Non-nil means truncate lines in all windows less than full frame wide.");
truncate_partial_width_windows = 1;
DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
"nil means display the mode-line/header-line/menu-bar in the default face.\n\
Any other value means to use the appropriate face, `mode-line',\n\
`header-line', or `menu' respectively.\n\
\n\
This variable is deprecated; please change the above faces instead.");
mode_line_inverse_video = 1;
DEFVAR_LISP ("line-number-display-limit", &Vline_number_display_limit,
"*Maximum buffer size for which line number should be displayed.\n\
If the buffer is bigger than this, the line number does not appear\n\
in the mode line. A value of nil means no limit.");
Vline_number_display_limit = Qnil;
DEFVAR_INT ("line-number-display-limit-width",
&line_number_display_limit_width,
"*Maximum line width (in characters) for line number display.\n\
If the average length of the lines near point is bigger than this, then the\n\
line number may be omitted from the mode line.");
line_number_display_limit_width = 200;
DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
"*Non-nil means highlight region even in nonselected windows.");
highlight_nonselected_windows = 0;
DEFVAR_BOOL ("multiple-frames", &multiple_frames,
"Non-nil if more than one frame is visible on this display.\n\
Minibuffer-only frames don't count, but iconified frames do.\n\
This variable is not guaranteed to be accurate except while processing\n\
`frame-title-format' and `icon-title-format'.");
DEFVAR_LISP ("frame-title-format", &Vframe_title_format,
"Template for displaying the title bar of visible frames.\n\
\(Assuming the window manager supports this feature.)\n\
This variable has the same structure as `mode-line-format' (which see),\n\
and is used only on frames for which no explicit name has been set\n\
\(see `modify-frame-parameters').");
DEFVAR_LISP ("icon-title-format", &Vicon_title_format,
"Template for displaying the title bar of an iconified frame.\n\
\(Assuming the window manager supports this feature.)\n\
This variable has the same structure as `mode-line-format' (which see),\n\
and is used only on frames for which no explicit name has been set\n\
\(see `modify-frame-parameters').");
Vicon_title_format
= Vframe_title_format
= Fcons (intern ("multiple-frames"),
Fcons (build_string ("%b"),
Fcons (Fcons (build_string (""),
Fcons (intern ("invocation-name"),
Fcons (build_string ("@"),
Fcons (intern ("system-name"),
Qnil)))),
Qnil)));
DEFVAR_LISP ("message-log-max", &Vmessage_log_max,
"Maximum number of lines to keep in the message log buffer.\n\
If nil, disable message logging. If t, log messages but don't truncate\n\
the buffer when it becomes large.");
Vmessage_log_max = make_number (50);
DEFVAR_LISP ("window-size-change-functions", &Vwindow_size_change_functions,
"Functions called before redisplay, if window sizes have changed.\n\
The value should be a list of functions that take one argument.\n\
Just before redisplay, for each frame, if any of its windows have changed\n\
size since the last redisplay, or have been split or deleted,\n\
all the functions in the list are called, with the frame as argument.");
Vwindow_size_change_functions = Qnil;
DEFVAR_LISP ("window-scroll-functions", &Vwindow_scroll_functions,
"List of Functions to call before redisplaying a window with scrolling.\n\
Each function is called with two arguments, the window\n\
and its new display-start position. Note that the value of `window-end'\n\
is not valid when these functions are called.");
Vwindow_scroll_functions = Qnil;
DEFVAR_BOOL ("auto-resize-tool-bars", &auto_resize_tool_bars_p,
"*Non-nil means automatically resize tool-bars.\n\
This increases a tool-bar's height if not all tool-bar items are visible.\n\
It decreases a tool-bar's height when it would display blank lines\n\
otherwise.");
auto_resize_tool_bars_p = 1;
DEFVAR_BOOL ("auto-raise-tool-bar-buttons", &auto_raise_tool_bar_buttons_p,
"*Non-nil means raise tool-bar buttons when the mouse moves over them.");
auto_raise_tool_bar_buttons_p = 1;
DEFVAR_LISP ("tool-bar-button-margin", &Vtool_bar_button_margin,
"*Margin around tool-bar buttons in pixels.\n\
If an integer, use that for both horizontal and vertical margins.\n\
Otherwise, value should be a pair of integers `(HORZ : VERT)' with\n\
HORZ specifying the horizontal margin, and VERT specifying the\n\
vertical margin.");
Vtool_bar_button_margin = make_number (DEFAULT_TOOL_BAR_BUTTON_MARGIN);
DEFVAR_INT ("tool-bar-button-relief", &tool_bar_button_relief,
"Relief thickness of tool-bar buttons.");
tool_bar_button_relief = DEFAULT_TOOL_BAR_BUTTON_RELIEF;
DEFVAR_LISP ("fontification-functions", &Vfontification_functions,
"List of functions to call to fontify regions of text.\n\
Each function is called with one argument POS. Functions must\n\
fontify a region starting at POS in the current buffer, and give\n\
fontified regions the property `fontified'.\n\
This variable automatically becomes buffer-local when set.");
Vfontification_functions = Qnil;
Fmake_variable_buffer_local (Qfontification_functions);
DEFVAR_BOOL ("unibyte-display-via-language-environment",
&unibyte_display_via_language_environment,
"*Non-nil means display unibyte text according to language environment.\n\
Specifically this means that unibyte non-ASCII characters\n\
are displayed by converting them to the equivalent multibyte characters\n\
according to the current language environment. As a result, they are\n\
displayed according to the current fontset.");
unibyte_display_via_language_environment = 0;
DEFVAR_LISP ("max-mini-window-height", &Vmax_mini_window_height,
"*Maximum height for resizing mini-windows.\n\
If a float, it specifies a fraction of the mini-window frame's height.\n\
If an integer, it specifies a number of lines.");
Vmax_mini_window_height = make_float (0.25);
DEFVAR_LISP ("resize-mini-windows", &Vresize_mini_windows,
"*How to resize mini-windows.\n\
A value of nil means don't automatically resize mini-windows.\n\
A value of t means resize them to fit the text displayed in them.\n\
A value of `grow-only', the default, means let mini-windows grow\n\
only, until their display becomes empty, at which point the windows\n\
go back to their normal size.");
Vresize_mini_windows = Qgrow_only;
DEFVAR_BOOL ("cursor-in-non-selected-windows",
&cursor_in_non_selected_windows,
"*Non-nil means display a hollow cursor in non-selected windows.\n\
Nil means don't display a cursor there.");
cursor_in_non_selected_windows = 1;
DEFVAR_BOOL ("automatic-hscrolling", &automatic_hscrolling_p,
"*Non-nil means scroll the display automatically to make point visible.");
automatic_hscrolling_p = 1;
DEFVAR_LISP ("image-types", &Vimage_types,
"List of supported image types.\n\
Each element of the list is a symbol for a supported image type.");
Vimage_types = Qnil;
DEFVAR_BOOL ("message-truncate-lines", &message_truncate_lines,
"If non-nil, messages are truncated instead of resizing the echo area.\n\
Bind this around calls to `message' to let it take effect.");
message_truncate_lines = 0;
DEFVAR_LISP ("menu-bar-update-hook", &Vmenu_bar_update_hook,
"Normal hook run for clicks on menu bar, before displaying a submenu.\n\
Can be used to update submenus whose contents should vary.");
Vmenu_bar_update_hook = Qnil;
DEFVAR_BOOL ("inhibit-menubar-update", &inhibit_menubar_update,
"Non-nil means don't update menu bars. Internal use only.");
inhibit_menubar_update = 0;
DEFVAR_BOOL ("inhibit-eval-during-redisplay", &inhibit_eval_during_redisplay,
"Non-nil means don't eval Lisp during redisplay.");
inhibit_eval_during_redisplay = 0;
#if GLYPH_DEBUG
DEFVAR_BOOL ("inhibit-try-window-id", &inhibit_try_window_id,
"Inhibit try_window_id display optimization.");
inhibit_try_window_id = 0;
DEFVAR_BOOL ("inhibit-try-window-reusing", &inhibit_try_window_reusing,
"Inhibit try_window_reusing display optimization.");
inhibit_try_window_reusing = 0;
DEFVAR_BOOL ("inhibit-try-cursor-movement", &inhibit_try_cursor_movement,
"Inhibit try_cursor_movement display optimization.");
inhibit_try_cursor_movement = 0;
#endif
}
void
init_xdisp ()
{
Lisp_Object root_window;
struct window *mini_w;
current_header_line_height = current_mode_line_height = -1;
CHARPOS (this_line_start_pos) = 0;
mini_w = XWINDOW (minibuf_window);
root_window = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (mini_w)));
if (!noninteractive)
{
struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (root_window)));
int i;
XWINDOW (root_window)->top = make_number (FRAME_TOP_MARGIN (f));
set_window_height (root_window,
FRAME_HEIGHT (f) - 1 - FRAME_TOP_MARGIN (f),
0);
mini_w->top = make_number (FRAME_HEIGHT (f) - 1);
set_window_height (minibuf_window, 1, 0);
XWINDOW (root_window)->width = make_number (FRAME_WIDTH (f));
mini_w->width = make_number (FRAME_WIDTH (f));
scratch_glyph_row.glyphs[TEXT_AREA] = scratch_glyphs;
scratch_glyph_row.glyphs[TEXT_AREA + 1]
= scratch_glyphs + MAX_SCRATCH_GLYPHS;
for (i = 0; i < 3; ++i)
default_invis_vector[i] = make_number ('.');
}
#ifdef HAVE_WINDOW_SYSTEM
{
int size = 100;
frame_title_buf = (char *) xmalloc (size);
frame_title_buf_end = frame_title_buf + size;
frame_title_ptr = NULL;
}
#endif
help_echo_showing_p = 0;
}