#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 "keymap.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"
#include "blockinput.h"
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
#ifdef WINDOWSNT
#include "w32term.h"
#endif
#ifdef MAC_OS
#include "macterm.h"
#endif
#ifndef FRAME_X_OUTPUT
#define FRAME_X_OUTPUT(f) ((f)->output_data.x)
#endif
#define INFINITY 10000000
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
|| defined (USE_GTK)
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 Lisp_Object do_mouse_tracking;
extern int minibuffer_auto_raise;
extern Lisp_Object Vminibuffer_list;
extern Lisp_Object Qface;
extern Lisp_Object Qmode_line, Qmode_line_inactive, Qheader_line;
extern Lisp_Object Voverriding_local_map;
extern Lisp_Object Voverriding_local_map_menu_flag;
extern Lisp_Object Qmenu_item;
extern Lisp_Object Qwhen;
extern Lisp_Object Qhelp_echo;
Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
Lisp_Object Qredisplay_end_trigger_functions, Vredisplay_end_trigger_functions;
Lisp_Object Qinhibit_point_motion_hooks;
Lisp_Object QCeval, QCfile, QCdata, QCpropertize;
Lisp_Object Qfontified;
Lisp_Object Qgrow_only;
Lisp_Object Qinhibit_eval_during_redisplay;
Lisp_Object Qbuffer_position, Qposition, Qobject;
Lisp_Object Qbar, Qhbar, Qbox, Qhollow;
Lisp_Object Qarrow, Qhand, Qtext;
Lisp_Object Qrisky_local_variable;
Lisp_Object list_of_error;
Lisp_Object Vfontification_functions;
Lisp_Object Qfontification_functions;
Lisp_Object Vmouse_autoselect_window;
int auto_raise_tool_bar_buttons_p;
int make_cursor_line_fully_visible_p;
Lisp_Object Vtool_bar_border;
Lisp_Object Vtool_bar_button_margin;
EMACS_INT tool_bar_button_relief;
Lisp_Object Vauto_resize_tool_bars;
int x_stretch_cursor_p;
Lisp_Object Vinhibit_redisplay, Qinhibit_redisplay;
int inhibit_eval_during_redisplay;
Lisp_Object Qdisplay;
extern Lisp_Object Qface, Qinvisible, Qwidth;
Lisp_Object Vdisplay_pixels_per_inch;
Lisp_Object Qspace, QCalign_to, QCrelative_width, QCrelative_height;
Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise;
Lisp_Object Qslice;
Lisp_Object Qcenter;
Lisp_Object Qmargin, Qpointer;
Lisp_Object Qline_height;
extern Lisp_Object Qheight;
extern Lisp_Object QCwidth, QCheight, QCascent;
extern Lisp_Object Qscroll_bar;
extern Lisp_Object Qcursor;
Lisp_Object Vshow_trailing_whitespace;
Lisp_Object Vnobreak_char_display;
#ifdef HAVE_WINDOW_SYSTEM
extern Lisp_Object Voverflow_newline_into_fringe;
#define IT_OVERFLOW_NEWLINE_INTO_FRINGE(it) \
(!NILP (Voverflow_newline_into_fringe) \
&& FRAME_WINDOW_P (it->f) \
&& WINDOW_RIGHT_FRINGE_WIDTH (it->w) > 0 \
&& it->current_x == it->last_visible_x)
#endif
Lisp_Object Vvoid_text_area_pointer;
Lisp_Object Qtrailing_whitespace;
Lisp_Object Qescape_glyph;
Lisp_Object Qnobreak_space;
Lisp_Object Qimage;
Lisp_Object QCmap, QCpointer;
Lisp_Object Qrect, Qcircle, Qpoly;
int noninteractive_need_newline;
static int message_log_need_newline;
static Lisp_Object message_dolog_marker1;
static Lisp_Object message_dolog_marker2;
static Lisp_Object message_dolog_marker3;
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_variable_list;
Lisp_Object Voverlay_arrow_position;
Lisp_Object Voverlay_arrow_string;
Lisp_Object Qlast_arrow_position, Qlast_arrow_string;
Lisp_Object Qoverlay_arrow_string, Qoverlay_arrow_bitmap;
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 EMACS_INT scroll_step;
static EMACS_INT scroll_conservatively;
EMACS_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;
Lisp_Object echo_area_window;
Lisp_Object Vmessage_stack;
int message_enable_multibyte;
int update_mode_lines;
int windows_or_buffers_changed;
int cursor_type_changed;
int line_number_displayed;
Lisp_Object Vline_number_display_limit;
static EMACS_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 Vmenu_updating_frame;
Lisp_Object Vmax_mini_window_height;
int message_truncate_lines;
Lisp_Object Qmessage_truncate_lines;
static int message_cleared_p;
Lisp_Object Vblink_cursor_alist;
#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;
EMACS_INT hscroll_margin;
Lisp_Object Vhscroll_step;
Lisp_Object Vresize_mini_windows;
struct buffer *displayed_buffer;
EMACS_INT overline_margin;
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
};
#define CLEAR_FACE_CACHE_COUNT 500
static int clear_face_cache_count;
#ifdef HAVE_WINDOW_SYSTEM
#define CLEAR_IMAGE_CACHE_COUNT 101
static int clear_image_cache_count;
#endif
static struct frame *previous_terminal_frame;
int redisplaying_p;
int inhibit_free_realized_faces;
Lisp_Object Qinhibit_free_realized_faces;
Lisp_Object help_echo_string;
Lisp_Object help_echo_window;
Lisp_Object help_echo_object;
int help_echo_pos;
Lisp_Object previous_help_echo_string;
static struct glyph_slice null_glyph_slice = { 0, 0, 0, 0 };
static void setup_for_ellipsis P_ ((struct it *, int));
static void mark_window_display_accurate_1 P_ ((struct window *, int));
static int single_display_spec_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));
#if 0
static int invisible_text_between_p P_ ((struct it *, int, int));
#endif
static void pint2str P_ ((char *, int, int));
static void pint2hrstr 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_mode_line_noprop_char P_ ((char));
static int store_mode_line_noprop P_ ((const unsigned char *, int, int));
static void x_consider_frame_title P_ ((Lisp_Object));
static void handle_stop P_ ((struct it *));
static int tool_bar_lines_needed P_ ((struct frame *, int *));
static int single_display_spec_intangible_p P_ ((Lisp_Object));
static void ensure_echo_area_buffers P_ ((void));
static Lisp_Object unwind_with_echo_area_buffer P_ ((Lisp_Object));
static 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_ ((const 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 *,
Lisp_Object));
static void extend_face_to_end_of_line P_ ((struct it *));
static int append_space_for_newline P_ ((struct it *, int));
static int cursor_row_fully_visible_p P_ ((struct window *, int, int));
static int try_scrolling P_ ((Lisp_Object, int, EMACS_INT, EMACS_INT, int, int));
static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *));
static int trailing_whitespace_p P_ ((int));
static int message_log_check_duplicate P_ ((int, int, int, int));
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 select_frame_for_redisplay P_ ((Lisp_Object));
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 Lisp_Object redisplay_window_error ();
static Lisp_Object redisplay_window_0 P_ ((Lisp_Object));
static Lisp_Object redisplay_window_1 P_ ((Lisp_Object));
static int update_menu_bar P_ ((struct frame *, int, int));
static int try_window_reusing_current_matrix P_ ((struct window *));
static int try_window_id P_ ((struct window *));
static int display_line P_ ((struct it *));
static 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, Lisp_Object, int));
static int store_mode_line_string P_ ((char *, Lisp_Object, int, int, int, Lisp_Object));
static char *decode_mode_spec P_ ((struct window *, int, int, int, int *));
static 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 int get_overlay_strings_1 P_ ((struct it *, int, int));
static void next_overlay_string P_ ((struct it *));
static void reseat P_ ((struct it *, struct text_pos, int));
static void reseat_1 P_ ((struct it *, struct text_pos, int));
static void back_to_previous_visible_line_start P_ ((struct it *));
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_ellipsis P_ ((struct it *));
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_spec 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 *, int));
static void notice_overwritten_cursor P_ ((struct window *,
enum glyph_row_area,
int, int, int, int));
#endif
INLINE int
window_text_bottom_y (w)
struct window *w;
{
int height = WINDOW_TOTAL_HEIGHT (w);
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;
{
int cols = XFASTINT (w->total_cols);
int pixels = 0;
if (!w->pseudo_window_p)
{
cols -= WINDOW_SCROLL_BAR_COLS (w);
if (area == TEXT_AREA)
{
if (INTEGERP (w->left_margin_cols))
cols -= XFASTINT (w->left_margin_cols);
if (INTEGERP (w->right_margin_cols))
cols -= XFASTINT (w->right_margin_cols);
pixels = -WINDOW_TOTAL_FRINGE_WIDTH (w);
}
else if (area == LEFT_MARGIN_AREA)
{
cols = (INTEGERP (w->left_margin_cols)
? XFASTINT (w->left_margin_cols) : 0);
pixels = 0;
}
else if (area == RIGHT_MARGIN_AREA)
{
cols = (INTEGERP (w->right_margin_cols)
? XFASTINT (w->right_margin_cols) : 0);
pixels = 0;
}
}
return cols * WINDOW_FRAME_COLUMN_WIDTH (w) + pixels;
}
INLINE int
window_box_height (w)
struct window *w;
{
struct frame *f = XFRAME (w->frame);
int height = WINDOW_TOTAL_HEIGHT (w);
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, CURRENT_MODE_LINE_FACE_ID (w));
}
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 max (0, height);
}
INLINE int
window_box_left_offset (w, area)
struct window *w;
int area;
{
int x;
if (w->pseudo_window_p)
return 0;
x = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w);
if (area == TEXT_AREA)
x += (WINDOW_LEFT_FRINGE_WIDTH (w)
+ window_box_width (w, LEFT_MARGIN_AREA));
else if (area == RIGHT_MARGIN_AREA)
x += (WINDOW_LEFT_FRINGE_WIDTH (w)
+ window_box_width (w, LEFT_MARGIN_AREA)
+ window_box_width (w, TEXT_AREA)
+ (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
? 0
: WINDOW_RIGHT_FRINGE_WIDTH (w)));
else if (area == LEFT_MARGIN_AREA
&& WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
x += WINDOW_LEFT_FRINGE_WIDTH (w);
return x;
}
INLINE int
window_box_right_offset (w, area)
struct window *w;
int area;
{
return window_box_left_offset (w, area) + window_box_width (w, area);
}
INLINE int
window_box_left (w, area)
struct window *w;
int area;
{
struct frame *f = XFRAME (w->frame);
int x;
if (w->pseudo_window_p)
return FRAME_INTERNAL_BORDER_WIDTH (f);
x = (WINDOW_LEFT_EDGE_X (w)
+ window_box_left_offset (w, 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;
{
if (box_width)
*box_width = window_box_width (w, area);
if (box_height)
*box_height = window_box_height (w);
if (box_x)
*box_x = window_box_left (w, area);
if (box_y)
{
*box_y = WINDOW_TOP_EDGE_Y (w);
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, x, y, rtop, rbot, rowh, vpos)
struct window *w;
int charpos, *x, *y, *rtop, *rbot, *rowh, *vpos;
{
struct it it;
struct text_pos top;
int visible_p = 0;
struct buffer *old_buffer = NULL;
if (noninteractive)
return visible_p;
if (XBUFFER (w->buffer) != current_buffer)
{
old_buffer = current_buffer;
set_buffer_internal_1 (XBUFFER (w->buffer));
}
SET_TEXT_POS_FROM_MARKER (top, w->start);
if (WINDOW_WANTS_MODELINE_P (w))
current_mode_line_height
= display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w),
current_buffer->mode_line_format);
if (WINDOW_WANTS_HEADER_LINE_P (w))
current_header_line_height
= display_mode_line (w, HEADER_LINE_FACE_ID,
current_buffer->header_line_format);
start_display (&it, w, top);
move_it_to (&it, charpos, -1, it.last_visible_y-1, -1,
(charpos >= 0 ? MOVE_TO_POS : 0) | MOVE_TO_Y);
if (charpos >= 0 && IT_CHARPOS (it) >= charpos)
{
int top_x = it.current_x;
int top_y = it.current_y;
int bottom_y = (last_height = 0, line_bottom_y (&it));
int window_top_y = WINDOW_HEADER_LINE_HEIGHT (w);
if (top_y < window_top_y)
visible_p = bottom_y > window_top_y;
else if (top_y < it.last_visible_y)
visible_p = 1;
if (visible_p)
{
*x = top_x;
*y = max (top_y + max (0, it.max_ascent - it.ascent), window_top_y);
*rtop = max (0, window_top_y - top_y);
*rbot = max (0, bottom_y - it.last_visible_y);
*rowh = max (0, (min (bottom_y, it.last_visible_y)
- max (top_y, window_top_y)));
*vpos = it.vpos;
}
}
else
{
struct it it2;
it2 = it;
if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n')
move_it_by_lines (&it, 1, 0);
if (charpos < IT_CHARPOS (it)
|| (it.what == IT_EOB && charpos == IT_CHARPOS (it)))
{
visible_p = 1;
move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
*x = it2.current_x;
*y = it2.current_y + it2.max_ascent - it2.ascent;
*rtop = max (0, -it2.current_y);
*rbot = max (0, ((it2.current_y + it2.max_ascent + it2.max_descent)
- it.last_visible_y));
*rowh = max (0, (min (it2.current_y + it2.max_ascent + it2.max_descent,
it.last_visible_y)
- max (it2.current_y,
WINDOW_HEADER_LINE_HEIGHT (w))));
*vpos = it2.vpos;
}
}
if (old_buffer)
set_buffer_internal_1 (old_buffer);
current_header_line_height = current_mode_line_height = -1;
if (visible_p && XFASTINT (w->hscroll) > 0)
*x -= XFASTINT (w->hscroll) * WINDOW_FRAME_COLUMN_WIDTH (w);
#if 0
if (visible_p)
fprintf (stderr, "+pv pt=%d vs=%d --> x=%d y=%d rt=%d rb=%d rh=%d vp=%d\n",
charpos, w->vscroll, *x, *y, *rtop, *rbot, *rowh, *vpos);
else
fprintf (stderr, "-pv pt=%d vs=%d\n", charpos, w->vscroll);
#endif
return visible_p;
}
static INLINE int
string_char_and_length (str, maxlen, len)
const 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 = SBYTES (string) - BYTEPOS (pos);
const unsigned char *p = SDATA (string) + 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);
}
int
estimate_mode_line_height (f, face_id)
struct frame *f;
enum face_id face_id;
{
#ifdef HAVE_WINDOW_SYSTEM
if (FRAME_WINDOW_P (f))
{
int height = FONT_HEIGHT (FRAME_FONT (f));
if (FRAME_FACE_CACHE (f))
{
struct face *face = FACE_FROM_ID (f, face_id);
if (face)
{
if (face->font)
height = FONT_HEIGHT (face->font);
if (face->box_line_width > 0)
height += 2 * face->box_line_width;
}
}
return height;
}
#endif
return 1;
}
void
pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
FRAME_PTR f;
register int pix_x, pix_y;
int *x, *y;
NativeRectangle *bounds;
int noclip;
{
#ifdef HAVE_WINDOW_SYSTEM
if (FRAME_WINDOW_P (f))
{
if (pix_x < 0)
pix_x -= FRAME_COLUMN_WIDTH (f) - 1;
if (pix_y < 0)
pix_y -= FRAME_LINE_HEIGHT (f) - 1;
pix_x = FRAME_PIXEL_X_TO_COL (f, pix_x);
pix_y = FRAME_PIXEL_Y_TO_LINE (f, pix_y);
if (bounds)
STORE_NATIVE_RECT (*bounds,
FRAME_COL_TO_PIXEL_X (f, pix_x),
FRAME_LINE_TO_PIXEL_Y (f, pix_y),
FRAME_COLUMN_WIDTH (f) - 1,
FRAME_LINE_HEIGHT (f) - 1);
if (!noclip)
{
if (pix_x < 0)
pix_x = 0;
else if (pix_x > FRAME_TOTAL_COLS (f))
pix_x = FRAME_TOTAL_COLS (f);
if (pix_y < 0)
pix_y = 0;
else if (pix_y > FRAME_LINES (f))
pix_y = FRAME_LINES (f);
}
}
#endif
*x = pix_x;
*y = pix_y;
}
int
glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
struct window *w;
int hpos, vpos;
int *frame_x, *frame_y;
{
#ifdef HAVE_WINDOW_SYSTEM
if (FRAME_WINDOW_P (XFRAME (WINDOW_FRAME (w))))
{
int success_p;
xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
if (display_completed)
{
struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
struct glyph *glyph = row->glyphs[TEXT_AREA];
struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
hpos = row->x;
vpos = row->y;
while (glyph < end)
{
hpos += glyph->pixel_width;
++glyph;
}
if (hpos < 0)
hpos = 0;
success_p = 1;
}
else
{
hpos = vpos = 0;
success_p = 0;
}
*frame_x = WINDOW_TO_FRAME_PIXEL_X (w, hpos);
*frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, vpos);
return success_p;
}
#endif
*frame_x = hpos;
*frame_y = vpos;
return 1;
}
#ifdef HAVE_WINDOW_SYSTEM
static struct glyph *
x_y_to_hpos_vpos (w, x, y, hpos, vpos, dx, dy, area)
struct window *w;
int x, y;
int *hpos, *vpos, *dx, *dy, *area;
{
struct glyph *glyph, *end;
struct glyph_row *row = NULL;
int x0, i;
for (i = 0; i < w->current_matrix->nrows; ++i)
{
row = MATRIX_ROW (w->current_matrix, i);
if (!row->enabled_p)
return NULL;
if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
break;
}
*vpos = i;
*hpos = 0;
if (i == w->current_matrix->nrows)
return NULL;
if (w->pseudo_window_p)
{
*area = TEXT_AREA;
x0 = 0;
}
else
{
if (x < window_box_left_offset (w, TEXT_AREA))
{
*area = LEFT_MARGIN_AREA;
x0 = window_box_left_offset (w, LEFT_MARGIN_AREA);
}
else if (x < window_box_right_offset (w, TEXT_AREA))
{
*area = TEXT_AREA;
x0 = window_box_left_offset (w, TEXT_AREA) + min (row->x, 0);
}
else
{
*area = RIGHT_MARGIN_AREA;
x0 = window_box_left_offset (w, RIGHT_MARGIN_AREA);
}
}
glyph = row->glyphs[*area];
end = glyph + row->used[*area];
x -= x0;
while (glyph < end && x >= glyph->pixel_width)
{
x -= glyph->pixel_width;
++glyph;
}
if (glyph == end)
return NULL;
if (dx)
{
*dx = x;
*dy = y - (row->y + row->ascent - glyph->ascent);
}
*hpos = glyph - row->glyphs[*area];
return glyph;
}
void
frame_to_window_pixel_xy (w, x, y)
struct window *w;
int *x, *y;
{
if (w->pseudo_window_p)
{
struct frame *f = XFRAME (w->frame);
*x -= FRAME_INTERNAL_BORDER_WIDTH (f);
*y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
}
else
{
*x -= WINDOW_LEFT_EDGE_X (w);
*y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
}
}
int
get_glyph_string_clip_rects (s, rects, n)
struct glyph_string *s;
NativeRectangle *rects;
int n;
{
XRectangle r;
if (n <= 0)
return 0;
if (s->row->full_width_p)
{
r.x = WINDOW_LEFT_EDGE_X (s->w);
r.width = WINDOW_TOTAL_WIDTH (s->w);
if (s->w->pseudo_window_p)
r.height = s->row->visible_height;
else
r.height = s->height;
}
else
{
r.x = window_box_left (s->w, s->area);
r.width = window_box_width (s->w, s->area);
r.height = s->row->visible_height;
}
if (s->clip_head)
if (r.x < s->clip_head->x)
{
if (r.width >= s->clip_head->x - r.x)
r.width -= s->clip_head->x - r.x;
else
r.width = 0;
r.x = s->clip_head->x;
}
if (s->clip_tail)
if (r.x + r.width > s->clip_tail->x + s->clip_tail->background_width)
{
if (s->clip_tail->x + s->clip_tail->background_width >= r.x)
r.width = s->clip_tail->x + s->clip_tail->background_width - r.x;
else
r.width = 0;
}
if (s->for_overlaps)
{
r.y = WINDOW_HEADER_LINE_HEIGHT (s->w);
r.height = window_text_bottom_y (s->w) - r.y;
if (s->for_overlaps & OVERLAPS_ERASED_CURSOR)
{
XRectangle rc, r_save = r;
rc.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (s->w, s->w->phys_cursor.x);
rc.y = s->w->phys_cursor.y;
rc.width = s->w->phys_cursor_width;
rc.height = s->w->phys_cursor_height;
x_intersect_rectangles (&r_save, &rc, &r);
}
}
else
{
if (!s->row->full_width_p
&& MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
r.y = WINDOW_HEADER_LINE_HEIGHT (s->w);
else
r.y = max (0, s->row->y);
if (WINDOWP (s->f->tool_bar_window)
&& s->w == XWINDOW (s->f->tool_bar_window))
r.y -= FRAME_INTERNAL_BORDER_WIDTH (s->f);
}
r.y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r.y);
if (s->hl == DRAW_CURSOR)
{
struct glyph *glyph = s->first_glyph;
int height, max_y;
if (s->x > r.x)
{
r.width -= s->x - r.x;
r.x = s->x;
}
r.width = min (r.width, glyph->pixel_width);
height = min (glyph->ascent + glyph->descent,
min (FRAME_LINE_HEIGHT (s->f), s->row->visible_height));
max_y = window_text_bottom_y (s->w) - height;
max_y = WINDOW_TO_FRAME_PIXEL_Y (s->w, max_y);
if (s->ybase - glyph->ascent > max_y)
{
r.y = max_y;
r.height = height;
}
else
{
height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent);
if (height < r.height)
{
max_y = r.y + r.height;
r.y = min (max_y, max (r.y, s->ybase + glyph->descent - height));
r.height = min (max_y - r.y, height);
}
}
}
if ((s->for_overlaps & OVERLAPS_BOTH) == 0
|| ((s->for_overlaps & OVERLAPS_BOTH) == OVERLAPS_BOTH && n == 1))
{
#ifdef CONVERT_FROM_XRECT
CONVERT_FROM_XRECT (r, *rects);
#else
*rects = r;
#endif
return 1;
}
else
{
#ifdef CONVERT_FROM_XRECT
XRectangle rs[2];
#else
XRectangle *rs = rects;
#endif
int i = 0, row_y = WINDOW_TO_FRAME_PIXEL_Y (s->w, s->row->y);
if (s->for_overlaps & OVERLAPS_PRED)
{
rs[i] = r;
if (r.y + r.height > row_y)
{
if (r.y < row_y)
rs[i].height = row_y - r.y;
else
rs[i].height = 0;
}
i++;
}
if (s->for_overlaps & OVERLAPS_SUCC)
{
rs[i] = r;
if (r.y < row_y + s->row->visible_height)
{
if (r.y + r.height > row_y + s->row->visible_height)
{
rs[i].y = row_y + s->row->visible_height;
rs[i].height = r.y + r.height - rs[i].y;
}
else
rs[i].height = 0;
}
i++;
}
n = i;
#ifdef CONVERT_FROM_XRECT
for (i = 0; i < n; i++)
CONVERT_FROM_XRECT (rs[i], rects[i]);
#endif
return n;
}
}
void
get_glyph_string_clip_rect (s, nr)
struct glyph_string *s;
NativeRectangle *nr;
{
get_glyph_string_clip_rects (s, nr, 1);
}
void
get_phys_cursor_geometry (w, row, glyph, xp, yp, heightp)
struct window *w;
struct glyph_row *row;
struct glyph *glyph;
int *xp, *yp, *heightp;
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
int x, y, wd, h, h0, y0;
wd = glyph->pixel_width - 1;
#ifdef HAVE_NTGUI
wd++;
#endif
x = w->phys_cursor.x;
if (x < 0)
{
wd += x;
x = 0;
}
if (glyph->type == STRETCH_GLYPH
&& !x_stretch_cursor_p)
wd = min (FRAME_COLUMN_WIDTH (f), wd);
w->phys_cursor_width = wd;
y = w->phys_cursor.y + row->ascent - glyph->ascent;
h0 = min (FRAME_LINE_HEIGHT (f), row->visible_height);
h = max (h0, glyph->ascent + glyph->descent);
h0 = min (h0, glyph->ascent + glyph->descent);
y0 = WINDOW_HEADER_LINE_HEIGHT (w);
if (y < y0)
{
h = max (h - (y0 - y) + 1, h0);
y = y0 - 1;
}
else
{
y0 = window_text_bottom_y (w) - h0;
if (y > y0)
{
h += y - y0;
y = y0;
}
}
*xp = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, x);
*yp = WINDOW_TO_FRAME_PIXEL_Y (w, y);
*heightp = h;
}
void
remember_mouse_glyph (f, gx, gy, rect)
struct frame *f;
int gx, gy;
NativeRectangle *rect;
{
Lisp_Object window;
struct window *w;
struct glyph_row *r, *gr, *end_row;
enum window_part part;
enum glyph_row_area area;
int x, y, width, height;
if (!f->glyphs_initialized_p
|| (window = window_from_coordinates (f, gx, gy, &part, &x, &y, 0),
NILP (window)))
{
width = FRAME_SMALLEST_CHAR_WIDTH (f);
height = FRAME_SMALLEST_FONT_HEIGHT (f);
goto virtual_glyph;
}
w = XWINDOW (window);
width = WINDOW_FRAME_COLUMN_WIDTH (w);
height = WINDOW_FRAME_LINE_HEIGHT (w);
r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
if (w->pseudo_window_p)
{
area = TEXT_AREA;
part = ON_MODE_LINE;
goto text_glyph;
}
switch (part)
{
case ON_LEFT_MARGIN:
area = LEFT_MARGIN_AREA;
goto text_glyph;
case ON_RIGHT_MARGIN:
area = RIGHT_MARGIN_AREA;
goto text_glyph;
case ON_HEADER_LINE:
case ON_MODE_LINE:
gr = (part == ON_HEADER_LINE
? MATRIX_HEADER_LINE_ROW (w->current_matrix)
: MATRIX_MODE_LINE_ROW (w->current_matrix));
gy = gr->y;
area = TEXT_AREA;
goto text_glyph_row_found;
case ON_TEXT:
area = TEXT_AREA;
text_glyph:
gr = 0; gy = 0;
for (; r <= end_row && r->enabled_p; ++r)
if (r->y + r->height > y)
{
gr = r; gy = r->y;
break;
}
text_glyph_row_found:
if (gr && gy <= y)
{
struct glyph *g = gr->glyphs[area];
struct glyph *end = g + gr->used[area];
height = gr->height;
for (gx = gr->x; g < end; gx += g->pixel_width, ++g)
if (gx + g->pixel_width > x)
break;
if (g < end)
{
if (g->type == IMAGE_GLYPH)
{
STORE_NATIVE_RECT (*rect, 0, 0, 0, 0);
return;
}
width = g->pixel_width;
}
else
{
x -= gx;
gx += (x / width) * width;
}
if (part != ON_MODE_LINE && part != ON_HEADER_LINE)
gx += window_box_left_offset (w, area);
}
else
{
gx = (x / width) * width;
y -= gy;
gy += (y / height) * height;
}
break;
case ON_LEFT_FRINGE:
gx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
? WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
: window_box_right_offset (w, LEFT_MARGIN_AREA));
width = WINDOW_LEFT_FRINGE_WIDTH (w);
goto row_glyph;
case ON_RIGHT_FRINGE:
gx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
? window_box_right_offset (w, RIGHT_MARGIN_AREA)
: window_box_right_offset (w, TEXT_AREA));
width = WINDOW_RIGHT_FRINGE_WIDTH (w);
goto row_glyph;
case ON_SCROLL_BAR:
gx = (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
? 0
: (window_box_right_offset (w, RIGHT_MARGIN_AREA)
+ (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
? WINDOW_RIGHT_FRINGE_WIDTH (w)
: 0)));
width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
row_glyph:
gr = 0, gy = 0;
for (; r <= end_row && r->enabled_p; ++r)
if (r->y + r->height > y)
{
gr = r; gy = r->y;
break;
}
if (gr && gy <= y)
height = gr->height;
else
{
y -= gy;
gy += (y / height) * height;
}
break;
default:
;
virtual_glyph:
if (gx < 0)
gx -= width - 1;
if (gy < 0)
gy -= height - 1;
gx = (gx / width) * width;
gy = (gy / height) * height;
goto store_rect;
}
gx += WINDOW_LEFT_EDGE_X (w);
gy += WINDOW_TOP_EDGE_Y (w);
store_rect:
STORE_NATIVE_RECT (*rect, gx, gy, width, height);
#if 0
#if HAVE_X_WINDOWS
XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f->output_data.x->normal_gc,
gx, gy, width, height);
#endif
#endif
}
#endif
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 = SPECPDL_INDEX ();
struct gcpro gcpro1;
GCPRO1 (sexpr);
specbind (Qinhibit_redisplay, Qt);
val = internal_condition_case_1 (Feval, sexpr, Qt,
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 = SPECPDL_INDEX ();
struct gcpro gcpro1;
GCPRO1 (args[0]);
gcpro1.nvars = nargs;
specbind (Qinhibit_redisplay, Qt);
val = internal_condition_case_2 (Ffuncall, nargs, args, Qt,
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 == GET_FROM_STRING)
{
xassert (STRINGP (it->string));
xassert (IT_STRING_CHARPOS (*it) >= 0);
}
else
{
xassert (IT_STRING_CHARPOS (*it) < 0);
if (it->method == GET_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 >= BUF_BEG (current_buffer)
&& charpos <= ZV));
if (face_change_count && !inhibit_free_realized_faces)
{
face_change_count = 0;
free_all_realized_faces (Qnil);
}
if (row == NULL)
{
if (base_face_id == MODE_LINE_FACE_ID
|| base_face_id == MODE_LINE_INACTIVE_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;
it->string = Qnil;
IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1;
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 (FLOATP (current_buffer->extra_line_spacing))
it->extra_line_spacing = (XFLOAT_DATA (current_buffer->extra_line_spacing)
* FRAME_LINE_HEIGHT (it->f));
else if (it->f->extra_line_spacing > 0)
it->extra_line_spacing = it->f->extra_line_spacing;
it->max_extra_line_spacing = 0;
}
if (noninteractive && 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->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil;
it->space_width = Qnil;
it->font_height = Qnil;
it->override_ascent = -1;
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 (minibuf_selected_window)
&& w == XWINDOW (minibuf_selected_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 = WINDOW_TOTAL_WIDTH (w);
}
else
{
it->first_visible_x
= XFASTINT (it->w->hscroll) * FRAME_COLUMN_WIDTH (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_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 >= BUF_BEG (current_buffer))
{
it->end_charpos = ZV;
it->face_id = -1;
IT_CHARPOS (*it) = charpos;
if (bytepos < charpos)
IT_BYTEPOS (*it) = CHAR_TO_BYTE (charpos);
else
IT_BYTEPOS (*it) = bytepos;
it->start = it->current;
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);
it->first_vpos = first_vpos;
if (it->method == GET_FROM_BUFFER && !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)
{
int new_x;
reseat_at_previous_visible_line_start (it);
move_it_to (it, CHARPOS (pos), -1, -1, -1, MOVE_TO_POS);
new_x = it->current_x + it->pixel_width;
if (it->current_x > 0
&& !it->truncate_lines_p
&& (
new_x > it->last_visible_x
|| (new_x == it->last_visible_x
&& FRAME_WINDOW_P (it->f))))
{
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);
ellipses_p = 2 == TEXT_PROP_MEANS_INVISIBLE (prop);
}
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 < OVERLAY_STRING_CHUNK_SIZE; ++i)
{
const char *s = SDATA (it->overlay_strings[i]);
const char *e = s + SBYTES (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 == GET_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 = GET_FROM_STRING;
}
#if 0
else if (it->current.overlay_string_index >= 0)
{
while (it->sp)
pop_it (it);
xassert (it->current.overlay_string_index == -1);
xassert (it->method == GET_FROM_BUFFER);
if (CHARPOS (pos->pos) == ZV)
it->overlay_strings_at_end_processed_p = 1;
}
#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->start = 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;
struct props *p;
it->dpvec = NULL;
it->current.dpvec_index = -1;
handle_overlay_change_p = !it->ignore_overlay_strings_at_pos_p;
it->ignore_overlay_strings_at_pos_p = 0;
if (it->selective_display_ellipsis_p)
it->saved_face_id = it->face_id;
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)
{
if (!handle_overlay_change_p || it->sp > 1)
return;
if (!get_overlay_strings_1 (it, 0, 0))
return;
it->ignore_overlay_strings_at_pos_p = 1;
it->string_from_display_prop_p = 0;
handle_overlay_change_p = 0;
handled = HANDLED_RECOMPUTE_PROPS;
break;
}
else if (handled == HANDLED_OVERLAY_STRING_CONSUMED)
handle_overlay_change_p = 0;
}
if (handled != HANDLED_RECOMPUTE_PROPS)
{
if (it->method == GET_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 i;
GET_OVERLAYS_AT (pos, overlays, noverlays, &endpos, 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 (!NILP (Vmemory_full))
return handled;
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) && IT_CHARPOS (*it) < Z))
{
int count = SPECPDL_INDEX ();
Lisp_Object val;
val = Vfontification_functions;
specbind (Qfontification_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 = CURRENT_MODE_LINE_FACE_ID (it->w);
#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) >= SCHARS (it->string)
|| (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))
{
const unsigned char *p = SDATA (it->string) + BYTEPOS (pos);
int rest = SBYTES (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 (BYTEPOS (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, SCHARS (it->string));
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
{
IT_STRING_CHARPOS (*it) = SCHARS (it->string);
IT_STRING_BYTEPOS (*it) = SBYTES (it->string);
}
}
}
}
else
{
int invis_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);
invis_p = TEXT_PROP_MEANS_INVISIBLE (prop);
if (invis_p && IT_CHARPOS (*it) < it->end_charpos)
{
int display_ellipsis_p = invis_p == 2;
handled = HANDLED_RECOMPUTE_PROPS;
do
{
newpos = skip_invisible (IT_CHARPOS (*it),
&next_stop, ZV, it->window);
if (newpos == IT_CHARPOS (*it) || newpos >= ZV)
invis_p = 0;
else
{
pos = make_number (newpos);
prop = Fget_char_property (pos, Qinvisible, it->window);
invis_p = TEXT_PROP_MEANS_INVISIBLE (prop);
}
if (invis_p)
IT_CHARPOS (*it) = next_stop;
if (invis_p == 2)
display_ellipsis_p = 1;
}
while (invis_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)
{
if (!STRINGP (it->object))
{
it->position.charpos = IT_CHARPOS (*it) - 1;
it->position.bytepos = CHAR_TO_BYTE (it->position.charpos);
}
setup_for_ellipsis (it, 0);
}
}
}
return handled;
}
static void
setup_for_ellipsis (it, len)
struct it *it;
int len;
{
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 = len;
it->current.dpvec_index = 0;
it->dpvec_face_id = -1;
if (it->saved_face_id < 0 || it->saved_face_id != it->face_id)
it->saved_face_id = it->face_id = DEFAULT_FACE_ID;
it->method = GET_FROM_DISPLAY_VECTOR;
it->ellipsis_p = 1;
}
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
{
XSETWINDOW (object, it->w);
position = &it->current.pos;
}
it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil;
it->space_width = Qnil;
it->font_height = 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 (!STRINGP (it->string))
object = it->w->buffer;
if (CONSP (prop)
&& !EQ (XCAR (prop), Qimage)
&& !EQ (XCAR (prop), Qspace)
&& !EQ (XCAR (prop), Qwhen)
&& !EQ (XCAR (prop), Qslice)
&& !EQ (XCAR (prop), Qspace_width)
&& !EQ (XCAR (prop), Qheight)
&& !EQ (XCAR (prop), Qraise)
&& !(CONSP (XCAR (prop)) && EQ (XCAR (XCAR (prop)), Qmargin))
&& !EQ (XCAR (prop), Qleft_fringe)
&& !EQ (XCAR (prop), Qright_fringe)
&& !NILP (XCAR (prop)))
{
for (; CONSP (prop); prop = XCDR (prop))
{
if (handle_single_display_spec (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_spec (it, AREF (prop, i), object,
position, display_replaced_p))
display_replaced_p = 1;
}
else
{
int ret = handle_single_display_spec (it, prop, object, position, 0);
if (ret < 0)
return HANDLED_RECOMPUTE_PROPS;
if (ret)
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_spec (it, spec, object, position,
display_replaced_before_p)
struct it *it;
Lisp_Object spec;
Lisp_Object object;
struct text_pos *position;
int display_replaced_before_p;
{
Lisp_Object form;
Lisp_Object location, value;
struct text_pos start_pos, save_pos;
int valid_p;
form = Qt;
if (CONSP (spec) && EQ (XCAR (spec), Qwhen))
{
spec = XCDR (spec);
if (!CONSP (spec))
return 0;
form = XCAR (spec);
spec = XCDR (spec);
}
if (!NILP (form) && !EQ (form, Qt))
{
int count = SPECPDL_INDEX ();
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 (spec)
&& EQ (XCAR (spec), Qheight)
&& CONSP (XCDR (spec)))
{
if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
return 0;
it->font_height = XCAR (XCDR (spec));
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
{
int count = SPECPDL_INDEX ();
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);
}
return 0;
}
if (CONSP (spec)
&& EQ (XCAR (spec), Qspace_width)
&& CONSP (XCDR (spec)))
{
if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
return 0;
value = XCAR (XCDR (spec));
if (NUMBERP (value) && XFLOATINT (value) > 0)
it->space_width = value;
return 0;
}
if (CONSP (spec)
&& EQ (XCAR (spec), Qslice))
{
Lisp_Object tem;
if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
return 0;
if (tem = XCDR (spec), CONSP (tem))
{
it->slice.x = XCAR (tem);
if (tem = XCDR (tem), CONSP (tem))
{
it->slice.y = XCAR (tem);
if (tem = XCDR (tem), CONSP (tem))
{
it->slice.width = XCAR (tem);
if (tem = XCDR (tem), CONSP (tem))
it->slice.height = XCAR (tem);
}
}
}
return 0;
}
if (CONSP (spec)
&& EQ (XCAR (spec), Qraise)
&& CONSP (XCDR (spec)))
{
if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
return 0;
#ifdef HAVE_WINDOW_SYSTEM
value = XCAR (XCDR (spec));
if (NUMBERP (value))
{
struct face *face = FACE_FROM_ID (it->f, it->face_id);
it->voffset = - (XFLOATINT (value)
* (FONT_HEIGHT (face->font)));
}
#endif
return 0;
}
if (it->string_from_display_prop_p)
return 0;
start_pos = *position;
*position = display_prop_end (it, object, start_pos);
value = Qnil;
it->stop_charpos = position->charpos;
if (CONSP (spec)
&& (EQ (XCAR (spec), Qleft_fringe)
|| EQ (XCAR (spec), Qright_fringe))
&& CONSP (XCDR (spec)))
{
int face_id = DEFAULT_FACE_ID;
int fringe_bitmap;
if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
return 0;
#ifdef HAVE_WINDOW_SYSTEM
value = XCAR (XCDR (spec));
if (!SYMBOLP (value)
|| !(fringe_bitmap = lookup_fringe_bitmap (value)))
return 0;
if (CONSP (XCDR (XCDR (spec))))
{
Lisp_Object face_name = XCAR (XCDR (XCDR (spec)));
int face_id2 = lookup_derived_face (it->f, face_name,
'A', FRINGE_FACE_ID, 0);
if (face_id2 >= 0)
face_id = face_id2;
}
save_pos = it->position;
it->position = *position;
push_it (it);
it->position = save_pos;
it->area = TEXT_AREA;
it->what = IT_IMAGE;
it->image_id = -1;
it->position = start_pos;
it->object = NILP (object) ? it->w->buffer : object;
it->method = GET_FROM_IMAGE;
it->face_id = face_id;
*position = start_pos;
if (EQ (XCAR (spec), Qleft_fringe))
{
it->left_user_fringe_bitmap = fringe_bitmap;
it->left_user_fringe_face_id = face_id;
}
else
{
it->right_user_fringe_bitmap = fringe_bitmap;
it->right_user_fringe_face_id = face_id;
}
#endif
return 1;
}
location = Qunbound;
if (CONSP (spec) && CONSP (XCAR (spec)))
{
Lisp_Object tem;
value = XCDR (spec);
if (CONSP (value))
value = XCAR (value);
tem = XCAR (spec);
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 = spec;
}
valid_p = (STRINGP (value)
#ifdef HAVE_WINDOW_SYSTEM
|| (!FRAME_TERMCAP_P (it->f) && valid_image_p (value))
#endif
|| (CONSP (value) && EQ (XCAR (value), Qspace)));
if (valid_p && !display_replaced_before_p)
{
save_pos = it->position;
it->position = *position;
push_it (it);
it->position = save_pos;
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))
{
if (SCHARS (value) == 0)
{
pop_it (it);
return -1;
}
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 = SCHARS (it->string);
it->method = GET_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 = GET_FROM_STRETCH;
it->object = value;
*position = 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 = GET_FROM_IMAGE;
*position = start_pos;
}
#endif
return 1;
}
*position = start_pos;
return 0;
}
static int
single_display_spec_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 (STRINGP (prop))
return 1;
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)
|| EQ (XCAR (prop), Qspace)));
}
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_spec_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_spec_intangible_p (AREF (prop, i)))
return 1;
}
else
return single_display_spec_intangible_p (prop);
return 0;
}
static int
single_display_spec_string_p (prop, string)
Lisp_Object prop, string;
{
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;
{
if (CONSP (prop)
&& CONSP (XCAR (prop))
&& !EQ (Qmargin, XCAR (XCAR (prop))))
{
while (CONSP (prop))
{
if (single_display_spec_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_spec_string_p (AREF (prop, i), string))
return 1;
}
else
return single_display_spec_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 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)
{
struct composition *cmp = composition_table[id];
if (cmp->glyph_len == 0)
{
if (STRINGP (it->string))
{
IT_STRING_CHARPOS (*it) = end;
IT_STRING_BYTEPOS (*it) = string_char_to_byte (it->string,
end);
}
else
{
IT_CHARPOS (*it) = end;
IT_BYTEPOS (*it) = CHAR_TO_BYTE (end);
}
return HANDLED_RECOMPUTE_PROPS;
}
it->stop_charpos = end;
push_it (it);
it->method = GET_FROM_COMPOSITION;
it->cmp_id = id;
it->cmp_len = COMPOSITION_LENGTH (prop);
it->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;
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->sp > 0
|| it->method == GET_FROM_COMPOSITION
|| (NILP (it->string)
&& it->method == GET_FROM_BUFFER
&& it->stop_charpos >= BEGV
&& it->stop_charpos <= it->end_charpos));
it->current.overlay_string_index = -1;
it->n_overlay_strings = 0;
if (IT_CHARPOS (*it) >= it->end_charpos)
it->overlay_strings_at_end_processed_p = 1;
if (display_ellipsis_p)
setup_for_ellipsis (it, 0);
}
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 = GET_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 overlay, window, str, invisible;
struct Lisp_Overlay *ov;
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; ov; ov = ov->next)
{
XSETMISC (overlay, 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))
&& SCHARS (str))
RECORD_OVERLAY_STRING (overlay, str, 0);
if ((end == charpos || (start == charpos && invis_p))
&& (str = Foverlay_get (overlay, Qafter_string), STRINGP (str))
&& SCHARS (str))
RECORD_OVERLAY_STRING (overlay, str, 1);
}
for (ov = current_buffer->overlays_after; ov; ov = ov->next)
{
XSETMISC (overlay, 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))
&& SCHARS (str))
RECORD_OVERLAY_STRING (overlay, str, 0);
if ((end == charpos || (start == charpos && invis_p))
&& (str = Foverlay_get (overlay, Qafter_string), STRINGP (str))
&& SCHARS (str))
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_1 (it, charpos, compute_stop_p)
struct it *it;
int charpos;
{
it->current.overlay_string_index = 0;
load_overlay_strings (it, charpos);
if (it->n_overlay_strings)
{
if (compute_stop_p)
compute_stop_pos (it);
xassert (it->face_id >= 0);
xassert (!compute_stop_p || 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;
xassert (STRINGP (it->string));
it->end_charpos = SCHARS (it->string);
it->multibyte_p = STRING_MULTIBYTE (it->string);
it->method = GET_FROM_STRING;
return 1;
}
it->current.overlay_string_index = -1;
return 0;
}
static int
get_overlay_strings (it, charpos)
struct it *it;
int charpos;
{
it->string = Qnil;
it->method = GET_FROM_BUFFER;
(void) get_overlay_strings_1 (it, charpos, 1);
CHECK_IT (it);
return STRINGP (it->string);
}
static void
push_it (it)
struct it *it;
{
struct iterator_stack_entry *p;
xassert (it->sp < IT_STACK_SIZE);
p = it->stack + it->sp;
p->stop_charpos = it->stop_charpos;
xassert (it->face_id >= 0);
p->face_id = it->face_id;
p->string = it->string;
p->method = it->method;
switch (p->method)
{
case GET_FROM_IMAGE:
p->u.image.object = it->object;
p->u.image.image_id = it->image_id;
p->u.image.slice = it->slice;
break;
case GET_FROM_COMPOSITION:
p->u.comp.object = it->object;
p->u.comp.c = it->c;
p->u.comp.len = it->len;
p->u.comp.cmp_id = it->cmp_id;
p->u.comp.cmp_len = it->cmp_len;
break;
case GET_FROM_STRETCH:
p->u.stretch.object = it->object;
break;
}
p->position = it->position;
p->current = it->current;
p->end_charpos = it->end_charpos;
p->string_nchars = it->string_nchars;
p->area = it->area;
p->multibyte_p = it->multibyte_p;
p->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->current = p->current;
it->position = p->position;
it->string = p->string;
if (NILP (it->string))
SET_TEXT_POS (it->current.string_pos, -1, -1);
it->method = p->method;
switch (it->method)
{
case GET_FROM_IMAGE:
it->image_id = p->u.image.image_id;
it->object = p->u.image.object;
it->slice = p->u.image.slice;
break;
case GET_FROM_COMPOSITION:
it->object = p->u.comp.object;
it->c = p->u.comp.c;
it->len = p->u.comp.len;
it->cmp_id = p->u.comp.cmp_id;
it->cmp_len = p->u.comp.cmp_len;
break;
case GET_FROM_STRETCH:
it->object = p->u.comp.object;
break;
case GET_FROM_BUFFER:
it->object = it->w->buffer;
break;
case GET_FROM_STRING:
it->object = it->string;
break;
}
it->end_charpos = p->end_charpos;
it->string_nchars = p->string_nchars;
it->area = p->area;
it->multibyte_p = p->multibyte_p;
it->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))
return 0;
newline_found_p = it->what == IT_CHARACTER && it->c == '\n';
set_iterator_to_next (it, 0);
}
if (!newline_found_p)
{
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;
{
while (IT_CHARPOS (*it) > BEGV)
{
back_to_previous_line_start (it);
if (IT_CHARPOS (*it) <= BEGV)
break;
if (it->selective > 0
&& indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
(double) it->selective))
continue;
{
Lisp_Object prop;
prop = Fget_char_property (make_number (IT_CHARPOS (*it) - 1),
Qinvisible, it->window);
if (TEXT_PROP_MEANS_INVISIBLE (prop))
continue;
}
if (IT_CHARPOS (*it) <= BEGV)
break;
{
struct it it2;
int pos;
int beg, end;
Lisp_Object val, overlay;
if (find_composition (IT_CHARPOS (*it), -1, &beg, &end, &val, Qnil)
&& beg < IT_CHARPOS (*it))
goto replaced;
it2 = *it;
pos = --IT_CHARPOS (it2);
--IT_BYTEPOS (it2);
it2.sp = 0;
if (handle_display_prop (&it2) == HANDLED_RETURN
&& !NILP (val = get_char_property_and_overlay
(make_number (pos), Qdisplay, Qnil, &overlay))
&& (OVERLAYP (overlay)
? (beg = OVERLAY_POSITION (OVERLAY_START (overlay)))
: get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil)))
goto replaced;
break;
replaced:
if (beg < BEGV)
beg = BEGV;
IT_CHARPOS (*it) = beg;
IT_BYTEPOS (*it) = buf_charpos_to_bytepos (current_buffer, beg);
}
}
it->continuation_lines_width = 0;
xassert (IT_CHARPOS (*it) >= BEGV);
xassert (IT_CHARPOS (*it) == BEGV
|| FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
CHECK_IT (it);
}
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),
(double) it->selective))
{
xassert (IT_BYTEPOS (*it) == BEGV
|| 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;
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 = GET_FROM_BUFFER;
it->object = it->w->buffer;
it->area = TEXT_AREA;
it->multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
it->sp = 0;
it->string_from_display_prop_p = 0;
it->face_before_selective_p = 0;
if (set_stop_p)
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 = SCHARS (string);
it->method = GET_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 = GET_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);
}
static int (* get_next_element[NUM_IT_METHODS]) P_ ((struct it *it)) =
{
next_element_from_buffer,
next_element_from_display_vector,
next_element_from_composition,
next_element_from_string,
next_element_from_c_string,
next_element_from_image,
next_element_from_stretch
};
static struct frame *last_escape_glyph_frame = NULL;
static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS);
static int last_escape_glyph_merged_face_id = 0;
int
get_next_display_element (it)
struct it *it;
{
int success_p;
get_next:
success_p = (*get_next_element[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->dpvec_face_id = -1;
it->saved_face_id = it->face_id;
it->method = GET_FROM_DISPLAY_VECTOR;
it->ellipsis_p = 0;
}
else
{
set_iterator_to_next (it, 0);
}
goto get_next;
}
else if ((it->c < ' '
&& (it->area != TEXT_AREA
|| (it->c != '\t'
&& it->glyph_row && it->glyph_row->mode_line_p)
|| (it->c != '\n' && it->c != '\t')))
|| (it->multibyte_p
? ((it->c >= 127
&& it->len == 1)
|| !CHAR_PRINTABLE_P (it->c)
|| (!NILP (Vnobreak_char_display)
&& (it->c == 0x8a0 || it->c == 0x8ad
|| it->c == 0x920 || it->c == 0x92d
|| it->c == 0xe20 || it->c == 0xe2d
|| it->c == 0xf20 || it->c == 0xf2d)))
: (it->c >= 127
&& (!unibyte_display_via_language_environment
|| it->c == unibyte_char_to_multibyte (it->c)))))
{
GLYPH g;
int ctl_len;
int face_id, lface_id = 0 ;
GLYPH escape_glyph;
if (it->c < 128 && it->ctl_arrow_p)
{
g = '^';
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));
lface_id = FAST_GLYPH_FACE (g);
}
if (lface_id)
{
g = FAST_GLYPH_CHAR (g);
face_id = merge_faces (it->f, Qt, lface_id,
it->face_id);
}
else if (it->f == last_escape_glyph_frame
&& it->face_id == last_escape_glyph_face_id)
{
face_id = last_escape_glyph_merged_face_id;
}
else
{
face_id = merge_faces (it->f, Qescape_glyph, 0,
it->face_id);
last_escape_glyph_frame = it->f;
last_escape_glyph_face_id = it->face_id;
last_escape_glyph_merged_face_id = face_id;
}
XSETINT (it->ctl_chars[0], g);
g = it->c ^ 0100;
XSETINT (it->ctl_chars[1], g);
ctl_len = 2;
goto display_control;
}
if (EQ (Vnobreak_char_display, Qt)
&& (it->c == 0x8a0 || it->c == 0x920
|| it->c == 0xe20 || it->c == 0xf20))
{
face_id = merge_faces (it->f, Qnobreak_space, 0,
it->face_id);
g = it->c = ' ';
XSETINT (it->ctl_chars[0], g);
ctl_len = 1;
goto display_control;
}
escape_glyph = '\\';
if (it->dp
&& INTEGERP (DISP_ESCAPE_GLYPH (it->dp))
&& GLYPH_CHAR_VALID_P (XFASTINT (DISP_ESCAPE_GLYPH (it->dp))))
{
escape_glyph = XFASTINT (DISP_ESCAPE_GLYPH (it->dp));
lface_id = FAST_GLYPH_FACE (escape_glyph);
}
if (lface_id)
{
escape_glyph = FAST_GLYPH_CHAR (escape_glyph);
face_id = merge_faces (it->f, Qt, lface_id,
it->face_id);
}
else if (it->f == last_escape_glyph_frame
&& it->face_id == last_escape_glyph_face_id)
{
face_id = last_escape_glyph_merged_face_id;
}
else
{
face_id = merge_faces (it->f, Qescape_glyph, 0,
it->face_id);
last_escape_glyph_frame = it->f;
last_escape_glyph_face_id = it->face_id;
last_escape_glyph_merged_face_id = face_id;
}
if (EQ (Vnobreak_char_display, Qt)
&& (it->c == 0x8ad || it->c == 0x92d
|| it->c == 0xe2d || it->c == 0xf2d))
{
g = it->c = '-';
XSETINT (it->ctl_chars[0], g);
ctl_len = 1;
goto display_control;
}
if (it->c == 0x8a0 || it->c == 0x8ad
|| it->c == 0x920 || it->c == 0x92d
|| it->c == 0xe20 || it->c == 0xe2d
|| it->c == 0xf20 || it->c == 0xf2d)
{
XSETINT (it->ctl_chars[0], escape_glyph);
g = it->c = ((it->c & 0xf) == 0 ? ' ' : '-');
XSETINT (it->ctl_chars[1], g);
ctl_len = 2;
goto display_control;
}
{
unsigned char str[MAX_MULTIBYTE_LENGTH];
int len;
int i;
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 = ((str[i] >> 6) & 7) + '0';
XSETINT (it->ctl_chars[i * 4 + 1], g);
g = ((str[i] >> 3) & 7) + '0';
XSETINT (it->ctl_chars[i * 4 + 2], g);
g = (str[i] & 7) + '0';
XSETINT (it->ctl_chars[i * 4 + 3], g);
}
ctl_len = len * 4;
}
display_control:
it->dpvec_char_len = it->len;
it->dpvec = it->ctl_chars;
it->dpend = it->dpvec + ctl_len;
it->current.dpvec_index = 0;
it->dpvec_face_id = face_id;
it->saved_face_id = it->face_id;
it->method = GET_FROM_DISPLAY_VECTOR;
it->ellipsis_p = 0;
goto get_next;
}
}
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;
switch (it->method)
{
case GET_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)));
}
break;
case GET_FROM_COMPOSITION:
xassert (it->cmp_id >= 0 && it->cmp_id < n_compositions);
xassert (it->sp > 0);
pop_it (it);
if (it->method == GET_FROM_STRING)
{
IT_STRING_BYTEPOS (*it) += it->len;
IT_STRING_CHARPOS (*it) += it->cmp_len;
goto consider_string_end;
}
else if (it->method == GET_FROM_BUFFER)
{
IT_BYTEPOS (*it) += it->len;
IT_CHARPOS (*it) += it->cmp_len;
}
break;
case GET_FROM_C_STRING:
IT_BYTEPOS (*it) += it->len;
IT_CHARPOS (*it) += 1;
break;
case GET_FROM_DISPLAY_VECTOR:
++it->current.dpvec_index;
it->face_id = it->saved_face_id;
if (it->dpvec + it->current.dpvec_index == it->dpend)
{
int recheck_faces = it->ellipsis_p;
if (it->s)
it->method = GET_FROM_C_STRING;
else if (STRINGP (it->string))
it->method = GET_FROM_STRING;
else
{
it->method = GET_FROM_BUFFER;
it->object = it->w->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)
{
if (it->method == GET_FROM_STRING
&& it->n_overlay_strings > 0)
it->ignore_overlay_strings_at_pos_p = 1;
it->len = it->dpvec_char_len;
set_iterator_to_next (it, reseat_p);
}
if (recheck_faces)
it->stop_charpos = IT_CHARPOS (*it);
}
break;
case GET_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) >= SCHARS (it->string))
next_overlay_string (it);
}
else
{
if (IT_STRING_CHARPOS (*it) == SCHARS (it->string)
&& it->sp > 0)
{
pop_it (it);
if (it->method == GET_FROM_STRING)
goto consider_string_end;
}
}
break;
case GET_FROM_IMAGE:
case GET_FROM_STRETCH:
xassert (it->sp > 0);
pop_it (it);
if (it->method == GET_FROM_STRING)
goto consider_string_end;
break;
default:
abort ();
}
xassert (it->method != GET_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->face_id = it->saved_face_id;
if (INTEGERP (*it->dpvec)
&& GLYPH_CHAR_VALID_P (XFASTINT (*it->dpvec)))
{
GLYPH g;
g = XFASTINT (it->dpvec[it->current.dpvec_index]);
it->c = FAST_GLYPH_CHAR (g);
it->len = CHAR_BYTES (it->c);
if (it->dpvec_face_id >= 0)
it->face_id = it->dpvec_face_id;
else
{
int lface_id = FAST_GLYPH_FACE (g);
if (lface_id > 0)
it->face_id = merge_faces (it->f, Qt, lface_id,
it->saved_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) >= SCHARS (it->string))
{
it->what = IT_EOB;
return 0;
}
else if (STRING_MULTIBYTE (it->string))
{
int remaining = SBYTES (it->string) - IT_STRING_BYTEPOS (*it);
const unsigned char *s = (SDATA (it->string)
+ IT_STRING_BYTEPOS (*it));
it->c = string_char_and_length (s, remaining, &it->len);
}
else
{
it->c = SREF (it->string, 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 = SBYTES (it->string) - IT_STRING_BYTEPOS (*it);
const unsigned char *s = (SDATA (it->string)
+ IT_STRING_BYTEPOS (*it));
it->c = string_char_and_length (s, maxlen, &it->len);
}
else
{
it->c = SREF (it->string, 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)
setup_for_ellipsis (it, it->len);
else
{
it->saved_face_id = it->face_id;
it->method = GET_FROM_BUFFER;
it->object = it->w->buffer;
reseat_at_next_visible_line_start (it, 1);
it->face_before_selective_p = 1;
}
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,
(double) 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);
if (STRINGP (it->string))
it->object = it->string;
else
it->object = it->w->buffer;
return 1;
}
#define IT_POS_VALID_AFTER_MOVE_P(it) \
((it)->method == GET_FROM_STRING \
? IT_STRING_CHARPOS (*it) == 0 \
: 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;
#define BUFFER_POS_REACHED_P() \
((op & MOVE_TO_POS) != 0 \
&& BUFFERP (it->object) \
&& IT_CHARPOS (*it) >= to_charpos \
&& (it->method == GET_FROM_BUFFER \
|| (it->method == GET_FROM_DISPLAY_VECTOR \
&& it->dpvec + it->current.dpvec_index + 1 >= it->dpend)))
while (1)
{
int x, i, ascent = 0, descent = 0;
if ((op & MOVE_TO_POS) != 0
&& BUFFERP (it->object)
&& it->method == GET_FROM_BUFFER
&& IT_CHARPOS (*it) > to_charpos)
{
result = MOVE_POS_MATCH_OR_ZV;
break;
}
if (!get_next_display_element (it)
|| (it->truncate_lines_p
&& BUFFER_POS_REACHED_P ()))
{
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;
int x_before_this_char = x;
int hpos_before_this_char = it->hpos;
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)
{
if (BUFFER_POS_REACHED_P ())
goto buffer_pos_reached;
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)
{
if (BUFFER_POS_REACHED_P ())
{
it->hpos = hpos_before_this_char;
it->current_x = x_before_this_char;
result = MOVE_POS_MATCH_OR_ZV;
break;
}
set_iterator_to_next (it, 1);
#ifdef HAVE_WINDOW_SYSTEM
if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
{
if (!get_next_display_element (it))
{
result = MOVE_POS_MATCH_OR_ZV;
break;
}
if (BUFFER_POS_REACHED_P ())
{
if (ITERATOR_AT_END_OF_LINE_P (it))
result = MOVE_POS_MATCH_OR_ZV;
else
result = MOVE_LINE_CONTINUED;
break;
}
if (ITERATOR_AT_END_OF_LINE_P (it))
{
result = MOVE_NEWLINE_OR_CR;
break;
}
}
#endif
}
}
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 (BUFFER_POS_REACHED_P ())
goto buffer_pos_reached;
else if (new_x > it->first_visible_x)
{
++it->hpos;
}
else
{
}
}
if (result != MOVE_UNDEFINED)
break;
}
else if (BUFFER_POS_REACHED_P ())
{
buffer_pos_reached:
it->current_x = x;
it->max_ascent = ascent;
it->max_descent = descent;
result = MOVE_POS_MATCH_OR_ZV;
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)
{
#ifdef HAVE_WINDOW_SYSTEM
if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
{
if (!get_next_display_element (it)
|| BUFFER_POS_REACHED_P ())
{
result = MOVE_POS_MATCH_OR_ZV;
break;
}
if (ITERATOR_AT_END_OF_LINE_P (it))
{
result = MOVE_NEWLINE_OR_CR;
break;
}
}
#endif
result = MOVE_LINE_TRUNCATED;
break;
}
}
#undef BUFFER_POS_REACHED_P
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 if (BUFFERP (it->object)
&& it->method == GET_FROM_BUFFER
&& IT_CHARPOS (*it) >= to_charpos)
skip = MOVE_POS_MATCH_OR_ZV;
else
skip = move_it_in_display_line_to (it, to_charpos, -1, MOVE_TO_POS);
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->c == '\t') ? it->last_visible_x : 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;
move_further_back:
xassert (dy >= 0);
start_pos = IT_CHARPOS (*it);
nlines = max (1, dy / FRAME_LINE_HEIGHT (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;
it->continuation_lines_width = 0;
it2 = *it;
it2.max_ascent = it2.max_descent = 0;
do
{
move_it_to (&it2, start_pos, -1, -1, it2.vpos + 1,
MOVE_TO_POS | MOVE_TO_VPOS);
}
while (!IT_POS_VALID_AFTER_MOVE_P (&it2));
xassert (IT_CHARPOS (*it) >= BEGV);
it3 = it2;
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);
#if 0
xassert (IT_CHARPOS (*it) <= start_pos);
#endif
}
else
{
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
> min (window_box_height (it->w), line_height * 2 / 3))
&& IT_CHARPOS (*it) > BEGV)
{
TRACE_MOVE ((stderr, " not far enough -> move_vert %d\n",
target_y - it->current_y));
dy = it->current_y - target_y;
goto move_further_back;
}
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);
}
#if 0
xassert (IT_CHARPOS (*it) >= BEGV);
#endif
}
}
}
void
move_it_vertically (it, dy)
struct it *it;
int dy;
{
if (dy <= 0)
move_it_vertically_backward (it, -dy);
else
{
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
&& ZV > BEGV
&& 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);
last_height = 0;
}
else if (dvpos > 0)
{
move_it_to (it, -1, -1, -1, it->vpos + dvpos, MOVE_TO_VPOS);
if (!IT_POS_VALID_AFTER_MOVE_P (it))
move_it_to (it, IT_CHARPOS (*it) + 1, -1, -1, -1, MOVE_TO_POS);
}
else
{
struct it it2;
int start_charpos, i;
dvpos += it->vpos;
move_it_vertically_backward (it, 0);
dvpos -= it->vpos;
start_charpos = IT_CHARPOS (*it);
for (i = -dvpos; i > 0 && IT_CHARPOS (*it) > BEGV; --i)
back_to_previous_visible_line_start (it);
reseat (it, it->current.pos, 1);
while (!IT_POS_VALID_AFTER_MOVE_P (it))
{
dvpos += it->vpos;
move_it_vertically_backward (it, 0);
dvpos -= it->vpos;
if (IT_POS_VALID_AFTER_MOVE_P (it))
break;
back_to_previous_visible_line_start (it);
reseat (it, it->current.pos, 1);
dvpos--;
}
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;
it2 = *it;
move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS);
if (IT_CHARPOS (*it) >= start_charpos)
*it = it2;
}
}
}
int
in_display_vector_p (it)
struct it *it;
{
return (it->method == GET_FROM_DISPLAY_VECTOR
&& it->current.dpvec_index > 0
&& it->dpvec + it->current.dpvec_index != it->dpend);
}
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;
USE_SAFE_ALLOCA;
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 = SBYTES (msg) + 1;
SAFE_ALLOCA (buffer, char *, len);
bcopy (SDATA (msg), buffer, len);
message_dolog (buffer, len - 1, 1, 0);
SAFE_FREE ();
UNGCPRO;
}
void
message_log_maybe_newline ()
{
if (message_log_need_newline)
message_dolog ("", 0, 1, 0);
}
void
message_dolog (m, nbytes, nlflag, multibyte)
const char *m;
int nbytes, nlflag, multibyte;
{
if (!NILP (Vmemory_full))
return;
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;
old_deactivate_mark = Vdeactivate_mark;
oldbuf = current_buffer;
Fset_buffer (Fget_buffer_create (Vmessages_buffer_name));
current_buffer->undo_list = Qt;
oldpoint = message_dolog_marker1;
set_marker_restricted (oldpoint, make_number (PT), Qnil);
oldbegv = message_dolog_marker2;
set_marker_restricted (oldbegv, make_number (BEGV), Qnil);
oldzv = message_dolog_marker3;
set_marker_restricted (oldzv, make_number (ZV), Qnil);
GCPRO1 (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 += char_bytes)
{
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;
unchain_marker (XMARKER (oldpoint));
unchain_marker (XMARKER (oldbegv));
unchain_marker (XMARKER (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)
const 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)
const char *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 (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);
clear_message (1,1);
cancel_echoing ();
message_log_maybe_newline ();
if (STRINGP (m))
{
char *buffer;
USE_SAFE_ALLOCA;
SAFE_ALLOCA (buffer, char *, nbytes);
bcopy (SDATA (m), buffer, nbytes);
message_dolog (buffer, nbytes, 1, multibyte);
SAFE_FREE ();
}
message3_nolog (m, nbytes, multibyte);
UNGCPRO;
}
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 (SDATA (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;
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) && SCHARS (m) > 0)
{
set_message (NULL, m, nbytes, multibyte);
if (minibuffer_auto_raise)
Fraise_frame (frame);
echo_message_buffer = Qnil;
}
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;
{
CHECK_STRING (string);
if (noninteractive)
{
if (m)
{
if (noninteractive_need_newline)
putc ('\n', stderr);
noninteractive_need_newline = 0;
fprintf (stderr, m, SDATA (string));
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))
{
Lisp_Object args[2], message;
struct gcpro gcpro1, gcpro2;
args[0] = build_string (m);
args[1] = message = string;
GCPRO2 (args[0], message);
gcpro1.nvars = 2;
message = Fformat (2, args);
if (log)
message3 (message, SBYTES (message), STRING_MULTIBYTE (message));
else
message3_nolog (message, SBYTES (message), STRING_MULTIBYTE (message));
UNGCPRO;
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, SBYTES (string),
!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 = SPECPDL_INDEX ();
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;
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;
{
if (! FRAME_LIVE_P (XFRAME (selected_frame)))
Fkill_emacs (Qnil);
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 = SPECPDL_INDEX ();
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);
SET_TEXT_POS_FROM_MARKER (start, w->start);
clear_glyph_matrix (w->desired_matrix);
XSETWINDOW (window, w);
try_window (window, start, 0);
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));
set_marker_both (w->start, w->buffer,
BUF_BEGV (XBUFFER (w->buffer)),
BUF_BEGV_BYTE (XBUFFER (w->buffer)));
if (!NILP (Vinhibit_redisplay))
return 0;
if (NILP (Vresize_mini_windows)
|| (FRAME_X_P (f) && FRAME_X_OUTPUT (f) == NULL))
return 0;
if (!FRAME_MINIBUF_ONLY_P (f))
{
struct it it;
struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
int total_height = WINDOW_TOTAL_LINES (root) + WINDOW_TOTAL_LINES (w);
int height, max_height;
int unit = FRAME_LINE_HEIGHT (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_LINES (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 -= min (it.extra_line_spacing, it.max_extra_line_spacing);
height = (height + unit - 1) / unit;
}
if (height > max_height)
{
height = max_height;
init_iterator (&it, w, ZV, ZV_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 > WINDOW_TOTAL_LINES (w))
{
int old_height = WINDOW_TOTAL_LINES (w);
freeze_window_starts (f, 1);
grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
}
else if (height < WINDOW_TOTAL_LINES (w)
&& (exact_p || BEGV == ZV))
{
int old_height = WINDOW_TOTAL_LINES (w);
freeze_window_starts (f, 0);
shrink_mini_window (w);
window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
}
}
else
{
if (height > WINDOW_TOTAL_LINES (w))
{
int old_height = WINDOW_TOTAL_LINES (w);
freeze_window_starts (f, 1);
grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
}
else if (height < WINDOW_TOTAL_LINES (w))
{
int old_height = WINDOW_TOTAL_LINES (w);
freeze_window_starts (f, 0);
shrink_mini_window (w);
if (height)
{
freeze_window_starts (f, 1);
grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
}
window_height_changed_p = WINDOW_TOTAL_LINES (w) != 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);
}
void
restore_message ()
{
Lisp_Object msg;
xassert (CONSP (Vmessage_stack));
msg = XCAR (Vmessage_stack);
if (STRINGP (msg))
message3_nolog (msg, SBYTES (msg), STRING_MULTIBYTE (msg));
else
message3_nolog (msg, 0, 0);
}
Lisp_Object
pop_message_unwind (dummy)
Lisp_Object dummy;
{
pop_message ();
return Qnil;
}
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)
const char *s;
Lisp_Object string;
int nbytes, multibyte_p;
{
message_enable_multibyte
= ((s && multibyte_p)
|| (STRINGP (string) && STRING_MULTIBYTE (string)));
with_echo_area_buffer (0, 0, set_message_1,
(EMACS_INT) s, string, nbytes, multibyte_p);
message_buf_print = 0;
help_echo_showing_p = 0;
}
static int
set_message_1 (a1, a2, nbytes, multibyte_p)
EMACS_INT a1;
Lisp_Object a2;
EMACS_INT nbytes, multibyte_p;
{
const char *s = (const char *) a1;
Lisp_Object string = a2;
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);
Ferase_buffer ();
if (STRINGP (string))
{
int nchars;
if (nbytes == 0)
nbytes = SBYTES (string);
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;
const unsigned char *msg = (const 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;
int changed_count = 0;
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f))
{
if (f->resized_p)
{
Fredraw_frame (frame);
f->force_flush_display_p = 1;
}
clear_current_matrices (f);
changed_count++;
f->garbaged = 0;
f->resized_p = 0;
}
}
frame_garbaged = 0;
if (changed_count)
++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 MAC_OS8
#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 = SPECPDL_INDEX ();
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;
}
static char *mode_line_noprop_buf;
static char *mode_line_noprop_buf_end;
static char *mode_line_noprop_ptr;
#define MODE_LINE_NOPROP_LEN(start) \
((mode_line_noprop_ptr - mode_line_noprop_buf) - start)
static enum {
MODE_LINE_DISPLAY = 0,
MODE_LINE_TITLE,
MODE_LINE_NOPROP,
MODE_LINE_STRING
} mode_line_target;
static Lisp_Object mode_line_proptrans_alist;
static Lisp_Object mode_line_string_list;
static Lisp_Object mode_line_string_face;
static Lisp_Object mode_line_string_face_prop;
static Lisp_Object Vmode_line_unwind_vector;
static Lisp_Object
format_mode_line_unwind_data (obuf, save_proptrans)
struct buffer *obuf;
{
Lisp_Object vector;
vector = Vmode_line_unwind_vector;
Vmode_line_unwind_vector = Qnil;
if (NILP (vector))
vector = Fmake_vector (make_number (7), Qnil);
AREF (vector, 0) = make_number (mode_line_target);
AREF (vector, 1) = make_number (MODE_LINE_NOPROP_LEN (0));
AREF (vector, 2) = mode_line_string_list;
AREF (vector, 3) = (save_proptrans ? mode_line_proptrans_alist : Qt);
AREF (vector, 4) = mode_line_string_face;
AREF (vector, 5) = mode_line_string_face_prop;
if (obuf)
XSETBUFFER (AREF (vector, 6), obuf);
else
AREF (vector, 6) = Qnil;
return vector;
}
static Lisp_Object
unwind_format_mode_line (vector)
Lisp_Object vector;
{
mode_line_target = XINT (AREF (vector, 0));
mode_line_noprop_ptr = mode_line_noprop_buf + XINT (AREF (vector, 1));
mode_line_string_list = AREF (vector, 2);
if (! EQ (AREF (vector, 3), Qt))
mode_line_proptrans_alist = AREF (vector, 3);
mode_line_string_face = AREF (vector, 4);
mode_line_string_face_prop = AREF (vector, 5);
if (!NILP (AREF (vector, 6)))
{
set_buffer_internal_1 (XBUFFER (AREF (vector, 6)));
AREF (vector, 6) = Qnil;
}
Vmode_line_unwind_vector = vector;
return Qnil;
}
static void
#ifdef PROTOTYPES
store_mode_line_noprop_char (char c)
#else
store_mode_line_noprop_char (c)
char c;
#endif
{
if (mode_line_noprop_ptr == mode_line_noprop_buf_end)
{
int len = MODE_LINE_NOPROP_LEN (0);
int new_size = 2 * len * sizeof *mode_line_noprop_buf;
mode_line_noprop_buf = (char *) xrealloc (mode_line_noprop_buf, new_size);
mode_line_noprop_buf_end = mode_line_noprop_buf + new_size;
mode_line_noprop_ptr = mode_line_noprop_buf + len;
}
*mode_line_noprop_ptr++ = c;
}
static int
store_mode_line_noprop (str, field_width, precision)
const unsigned char *str;
int field_width, precision;
{
int n = 0;
int dummy, nbytes;
nbytes = strlen (str);
n += c_string_width (str, nbytes, precision, &dummy, &nbytes);
while (nbytes--)
store_mode_line_noprop_char (*str++);
while (field_width > 0
&& n < field_width)
{
store_mode_line_noprop_char (' ');
++n;
}
return n;
}
#ifdef HAVE_WINDOW_SYSTEM
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;
int title_start;
char *title;
int len;
struct it it;
int count = SPECPDL_INDEX ();
for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
{
Lisp_Object other_frame = XCAR (tail);
struct frame *tf = XFRAME (other_frame);
if (tf != f
&& FRAME_KBOARD (tf) == FRAME_KBOARD (f)
&& !FRAME_MINIBUF_ONLY_P (tf)
&& !EQ (other_frame, tip_frame)
&& (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf)))
break;
}
multiple_frames = CONSP (tail);
record_unwind_protect (unwind_format_mode_line,
format_mode_line_unwind_data (current_buffer, 0));
set_buffer_internal_1 (XBUFFER (XWINDOW (f->selected_window)->buffer));
fmt = FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format;
mode_line_target = MODE_LINE_TITLE;
title_start = MODE_LINE_NOPROP_LEN (0);
init_iterator (&it, XWINDOW (f->selected_window), -1, -1,
NULL, DEFAULT_FACE_ID);
display_mode_element (&it, 0, -1, -1, fmt, Qnil, 0);
len = MODE_LINE_NOPROP_LEN (title_start);
title = mode_line_noprop_buf + title_start;
unbind_to (count, Qnil);
if (! STRINGP (f->name)
|| SBYTES (f->name) != len
|| bcmp (title, SDATA (f->name), len) != 0)
x_implicitly_set_name (f, make_string (title, len), Qnil);
}
}
#endif
void
prepare_menu_bars ()
{
int all_windows;
struct gcpro gcpro1, gcpro2;
struct frame *f;
Lisp_Object tooltip_frame;
#ifdef HAVE_WINDOW_SYSTEM
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 = SPECPDL_INDEX ();
int menu_bar_hooks_run = 0;
record_unwind_save_match_data ();
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);
menu_bar_hooks_run = update_menu_bar (f, 0, menu_bar_hooks_run);
#ifdef HAVE_WINDOW_SYSTEM
update_tool_bar (f, 0);
#ifdef MAC_OS
mac_update_title_bar (f, 0);
#endif
#endif
UNGCPRO;
}
unbind_to (count, Qnil);
}
else
{
struct frame *sf = SELECTED_FRAME ();
update_menu_bar (sf, 1, 0);
#ifdef HAVE_WINDOW_SYSTEM
update_tool_bar (sf, 1);
#ifdef MAC_OS
mac_update_title_bar (sf, 1);
#endif
#endif
}
#ifdef USE_X_TOOLKIT
pending_menu_activation = 0;
#endif
}
static int
update_menu_bar (f, save_match_data, hooks_run)
struct frame *f;
int save_match_data;
int hooks_run;
{
Lisp_Object window;
register struct window *w;
if (inhibit_menubar_update)
return hooks_run;
window = FRAME_SELECTED_WINDOW (f);
w = XWINDOW (window);
#if 0
if (update_mode_lines)
w->update_mode_line = Qt;
#endif
if (FRAME_WINDOW_P (f)
?
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
|| defined (USE_GTK)
FRAME_EXTERNAL_MENU_BAR (f)
#else
FRAME_MENU_BAR_LINES (f) > 0
#endif
: FRAME_MENU_BAR_LINES (f) > 0)
{
if (windows_or_buffers_changed
|| update_mode_lines
|| ((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 = SPECPDL_INDEX ();
specbind (Qinhibit_menubar_update, Qt);
set_buffer_internal_1 (XBUFFER (w->buffer));
if (save_match_data)
record_unwind_save_match_data ();
if (NILP (Voverriding_local_map_menu_flag))
{
specbind (Qoverriding_terminal_local_map, Qnil);
specbind (Qoverriding_local_map, Qnil);
}
if (!hooks_run)
{
safe_run_hooks (Qactivate_menubar_hook);
if (! NILP (Vlucid_menu_bar_dirty_flag))
call0 (Qrecompute_lucid_menubar);
safe_run_hooks (Qmenu_bar_update_hook);
hooks_run = 1;
}
XSETFRAME (Vmenu_updating_frame, f);
FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
|| defined (USE_GTK)
if (FRAME_WINDOW_P (f))
{
#ifdef MAC_OS
if (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);
}
}
return hooks_run;
}
#ifdef HAVE_WINDOW_SYSTEM
struct cursor_pos output_cursor;
void
set_output_cursor (cursor)
struct cursor_pos *cursor;
{
output_cursor.hpos = cursor->hpos;
output_cursor.vpos = cursor->vpos;
output_cursor.x = cursor->x;
output_cursor.y = cursor->y;
}
void
x_cursor_to (vpos, hpos, y, x)
int vpos, hpos, y, x;
{
struct window *w;
if (updated_window)
w = updated_window;
else
w = XWINDOW (selected_window);
output_cursor.hpos = hpos;
output_cursor.vpos = vpos;
output_cursor.x = x;
output_cursor.y = y;
if (updated_window == NULL)
{
BLOCK_INPUT;
display_and_set_cursor (w, 1, hpos, vpos, x, y);
if (rif->flush_display_optional)
rif->flush_display_optional (SELECTED_FRAME ());
UNBLOCK_INPUT;
}
}
#endif
#ifdef HAVE_WINDOW_SYSTEM
FRAME_PTR last_mouse_frame;
int last_tool_bar_item;
static void
update_tool_bar (f, save_match_data)
struct frame *f;
int save_match_data;
{
#ifdef USE_GTK
int do_update = FRAME_EXTERNAL_TOOL_BAR (f);
#else
int do_update = WINDOWP (f->tool_bar_window)
&& WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0;
#endif
if (do_update)
{
Lisp_Object window;
struct window *w;
window = FRAME_SELECTED_WINDOW (f);
w = XWINDOW (window);
if (windows_or_buffers_changed
|| !NILP (w->update_mode_line)
|| update_mode_lines
|| ((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 = SPECPDL_INDEX ();
Lisp_Object new_tool_bar;
int new_n_tool_bar;
struct gcpro gcpro1;
set_buffer_internal_1 (XBUFFER (w->buffer));
if (save_match_data)
record_unwind_save_match_data ();
if (NILP (Voverriding_local_map_menu_flag))
{
specbind (Qoverriding_terminal_local_map, Qnil);
specbind (Qoverriding_local_map, Qnil);
}
GCPRO1 (new_tool_bar);
new_tool_bar = tool_bar_items (Fcopy_sequence (f->tool_bar_items),
&new_n_tool_bar);
if (new_n_tool_bar != f->n_tool_bar_items
|| NILP (Fequal (new_tool_bar, f->tool_bar_items)))
{
BLOCK_INPUT;
f->tool_bar_items = new_tool_bar;
f->n_tool_bar_items = new_n_tool_bar;
w->update_mode_line = Qt;
UNBLOCK_INPUT;
}
UNGCPRO;
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)
? SCHARS (f->desired_tool_bar_string)
: 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;
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 = SCHARS (f->desired_tool_bar_string);
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, height)
struct it *it;
int height;
{
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, n_glyphs_before, i, nglyphs;
struct it it_before;
if (!get_next_display_element (it))
{
if (height < 0 && !it->hpos)
return;
break;
}
n_glyphs_before = row->used[TEXT_AREA];
it_before = *it;
PRODUCE_GLYPHS (it);
nglyphs = row->used[TEXT_AREA] - n_glyphs_before;
i = 0;
x = it_before.current_x;
while (i < nglyphs)
{
struct glyph *glyph = row->glyphs[TEXT_AREA] + n_glyphs_before + i;
if (x + glyph->pixel_width > max_x)
{
row->used[TEXT_AREA] = n_glyphs_before;
*it = it_before;
if (n_glyphs_before == 0
&& (it->vpos > 0 || IT_STRING_CHARPOS (*it) < it->end_charpos-1))
break;
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;
if (!row->displays_text_p && !EQ (Vauto_resize_tool_bars, Qgrow_only))
it->face_id = DEFAULT_FACE_ID;
extend_face_to_end_of_line (it);
last = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA] - 1;
last->right_box_line_p = 1;
if (last == row->glyphs[TEXT_AREA])
last->left_box_line_p = 1;
if ((height -= it->max_ascent + it->max_descent) > 0)
{
height %= FRAME_LINE_HEIGHT (it->f);
it->max_ascent += height / 2;
it->max_descent += (height + 1) / 2;
}
compute_line_metrics (it);
if (!row->displays_text_p)
{
row->height = row->phys_height = it->last_visible_y - row->y;
row->visible_height = row->height;
row->ascent = row->phys_ascent = 0;
row->extra_line_spacing = 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;
}
#define MAX_FRAME_TOOL_BAR_HEIGHT(f) \
((FRAME_LINE_HEIGHT (f) * FRAME_LINES (f)))
static int
tool_bar_lines_needed (f, n_rows)
struct frame *f;
int *n_rows;
{
struct window *w = XWINDOW (f->tool_bar_window);
struct it it;
struct glyph_row *temp_row = MATRIX_MODE_LINE_ROW (w->desired_matrix);
init_iterator (&it, w, -1, -1, temp_row, TOOL_BAR_FACE_ID);
it.first_visible_x = 0;
it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
while (!ITERATOR_AT_END_P (&it))
{
clear_glyph_row (temp_row);
it.glyph_row = temp_row;
display_tool_bar_line (&it, -1);
}
clear_glyph_row (temp_row);
if (n_rows)
*n_rows = it.vpos > 0 ? it.vpos : -1;
return (it.current_y + FRAME_LINE_HEIGHT (f) - 1) / FRAME_LINE_HEIGHT (f);
}
DEFUN ("tool-bar-lines-needed", Ftool_bar_lines_needed, Stool_bar_lines_needed,
0, 1, 0,
doc: )
(frame)
Lisp_Object frame;
{
struct frame *f;
struct window *w;
int nlines = 0;
if (NILP (frame))
frame = selected_frame;
else
CHECK_FRAME (frame);
f = XFRAME (frame);
if (WINDOWP (f->tool_bar_window)
|| (w = XWINDOW (f->tool_bar_window),
WINDOW_TOTAL_LINES (w) > 0))
{
update_tool_bar (f, 1);
if (f->n_tool_bar_items)
{
build_desired_tool_bar_string (f);
nlines = tool_bar_lines_needed (f, NULL);
}
}
return make_number (nlines);
}
static int
redisplay_tool_bar (f)
struct frame *f;
{
struct window *w;
struct it it;
struct glyph_row *row;
#ifdef USE_GTK
if (FRAME_EXTERNAL_TOOL_BAR (f))
update_frame_tool_bar (f);
return 0;
#endif
if (!WINDOWP (f->tool_bar_window)
|| (w = XWINDOW (f->tool_bar_window),
WINDOW_TOTAL_LINES (w) == 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_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (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);
if (f->n_tool_bar_rows == 0)
{
int nlines;
if ((nlines = tool_bar_lines_needed (f, &f->n_tool_bar_rows),
nlines != WINDOW_TOTAL_LINES (w)))
{
extern Lisp_Object Qtool_bar_lines;
Lisp_Object frame;
int old_height = WINDOW_TOTAL_LINES (w);
XSETFRAME (frame, f);
Fmodify_frame_parameters (frame,
Fcons (Fcons (Qtool_bar_lines,
make_number (nlines)),
Qnil));
if (WINDOW_TOTAL_LINES (w) != old_height)
{
clear_glyph_matrix (w->desired_matrix);
fonts_changed_p = 1;
return 1;
}
}
}
if (f->n_tool_bar_rows > 0)
{
int border, rows, height, extra;
if (INTEGERP (Vtool_bar_border))
border = XINT (Vtool_bar_border);
else if (EQ (Vtool_bar_border, Qinternal_border_width))
border = FRAME_INTERNAL_BORDER_WIDTH (f);
else if (EQ (Vtool_bar_border, Qborder_width))
border = f->border_width;
else
border = 0;
if (border < 0)
border = 0;
rows = f->n_tool_bar_rows;
height = max (1, (it.last_visible_y - border) / rows);
extra = it.last_visible_y - border - height * rows;
while (it.current_y < it.last_visible_y)
{
int h = 0;
if (extra > 0 && rows-- > 0)
{
h = (extra + rows - 1) / rows;
extra -= h;
}
display_tool_bar_line (&it, height + h);
}
}
else
{
while (it.current_y < it.last_visible_y)
display_tool_bar_line (&it, 0);
}
w->desired_matrix->no_scrolling_p = 1;
w->must_be_updated_p = 1;
if (!NILP (Vauto_resize_tool_bars))
{
int max_tool_bar_height = MAX_FRAME_TOOL_BAR_HEIGHT (f);
int change_height_p = 0;
if (IT_STRING_CHARPOS (it) < it.end_charpos
&& it.current_y < max_tool_bar_height)
change_height_p = 1;
row = it.glyph_row - 1;
if (!row->displays_text_p
&& row->height >= FRAME_LINE_HEIGHT (f))
change_height_p = 1;
if (row->displays_text_p
&& MATRIX_ROW_BOTTOM_Y (row) > it.last_visible_y
&& MATRIX_ROW_BOTTOM_Y (row) < max_tool_bar_height)
change_height_p = 1;
if (change_height_p)
{
extern Lisp_Object Qtool_bar_lines;
Lisp_Object frame;
int old_height = WINDOW_TOTAL_LINES (w);
int nrows;
int nlines = tool_bar_lines_needed (f, &nrows);
change_height_p = ((EQ (Vauto_resize_tool_bars, Qgrow_only)
&& !f->minimize_tool_bar_window_p)
? (nlines > old_height)
: (nlines != old_height));
f->minimize_tool_bar_window_p = 0;
if (change_height_p)
{
XSETFRAME (frame, f);
Fmodify_frame_parameters (frame,
Fcons (Fcons (Qtool_bar_lines,
make_number (nlines)),
Qnil));
if (WINDOW_TOTAL_LINES (w) != old_height)
{
clear_glyph_matrix (w->desired_matrix);
f->n_tool_bar_rows = nrows;
fonts_changed_p = 1;
return 1;
}
}
}
}
f->minimize_tool_bar_window_p = 0;
return 0;
}
static 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 (SCHARS (f->current_tool_bar_string), 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;
}
static int
get_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
struct frame *f;
int x, y;
struct glyph **glyph;
int *hpos, *vpos, *prop_idx;
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
struct window *w = XWINDOW (f->tool_bar_window);
int area;
*glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, 0, 0, &area);
if (*glyph == NULL)
return -1;
if (!tool_bar_item_info (f, *glyph, prop_idx))
return -1;
if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
&& *vpos >= dpyinfo->mouse_face_beg_row
&& *vpos <= dpyinfo->mouse_face_end_row
&& (*vpos > dpyinfo->mouse_face_beg_row
|| *hpos >= dpyinfo->mouse_face_beg_col)
&& (*vpos < dpyinfo->mouse_face_end_row
|| *hpos < dpyinfo->mouse_face_end_col
|| dpyinfo->mouse_face_past_end))
return 0;
return 1;
}
void
handle_tool_bar_click (f, x, y, down_p, modifiers)
struct frame *f;
int x, y, down_p;
unsigned int modifiers;
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
struct window *w = XWINDOW (f->tool_bar_window);
int hpos, vpos, prop_idx;
struct glyph *glyph;
Lisp_Object enabled_p;
frame_to_window_pixel_xy (w, &x, &y);
if (get_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
return;
enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
if (NILP (enabled_p))
return;
if (down_p)
{
show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
last_tool_bar_item = prop_idx;
}
else
{
Lisp_Object key, frame;
struct input_event event;
EVENT_INIT (event);
show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
XSETFRAME (frame, f);
event.kind = TOOL_BAR_EVENT;
event.frame_or_window = frame;
event.arg = frame;
kbd_buffer_store_event (&event);
event.kind = TOOL_BAR_EVENT;
event.frame_or_window = frame;
event.arg = key;
event.modifiers = modifiers;
kbd_buffer_store_event (&event);
last_tool_bar_item = -1;
}
}
static void
note_tool_bar_highlight (f, x, y)
struct frame *f;
int x, y;
{
Lisp_Object window = f->tool_bar_window;
struct window *w = XWINDOW (window);
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
int hpos, vpos;
struct glyph *glyph;
struct glyph_row *row;
int i;
Lisp_Object enabled_p;
int prop_idx;
enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
int mouse_down_p, rc;
if (x <= 0 || y <= 0)
{
clear_mouse_face (dpyinfo);
return;
}
rc = get_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
if (rc < 0)
{
clear_mouse_face (dpyinfo);
return;
}
else if (rc == 0)
goto set_help_echo;
clear_mouse_face (dpyinfo);
mouse_down_p = (dpyinfo->grabbed
&& f == last_mouse_frame
&& FRAME_LIVE_P (f));
if (mouse_down_p
&& last_tool_bar_item != prop_idx)
return;
dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
if (!NILP (enabled_p))
{
row = MATRIX_ROW (w->current_matrix, vpos);
for (i = x = 0; i < hpos; ++i)
x += row->glyphs[TEXT_AREA][i].pixel_width;
dpyinfo->mouse_face_beg_col = hpos;
dpyinfo->mouse_face_beg_row = vpos;
dpyinfo->mouse_face_beg_x = x;
dpyinfo->mouse_face_beg_y = row->y;
dpyinfo->mouse_face_past_end = 0;
dpyinfo->mouse_face_end_col = hpos + 1;
dpyinfo->mouse_face_end_row = vpos;
dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
dpyinfo->mouse_face_end_y = row->y;
dpyinfo->mouse_face_window = window;
dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
show_mouse_face (dpyinfo, draw);
dpyinfo->mouse_face_image_state = draw;
}
set_help_echo:
help_echo_object = help_echo_window = Qnil;
help_echo_pos = -1;
help_echo_string = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
if (NILP (help_echo_string))
help_echo_string = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
}
#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;
int hscroll_relative_p = FLOATP (Vhscroll_step);
int hscroll_step_abs = 0;
double hscroll_step_rel = 0;
if (hscroll_relative_p)
{
hscroll_step_rel = XFLOAT_DATA (Vhscroll_step);
if (hscroll_step_rel < 0)
{
hscroll_relative_p = 0;
hscroll_step_abs = 0;
}
}
else if (INTEGERP (Vhscroll_step))
{
hscroll_step_abs = XINT (Vhscroll_step);
if (hscroll_step_abs < 0)
hscroll_step_abs = 0;
}
else
hscroll_step_abs = 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 h_margin;
int text_area_width;
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);
text_area_width = window_box_width (w, TEXT_AREA);
h_margin = hscroll_margin * WINDOW_FRAME_COLUMN_WIDTH (w);
if ((XFASTINT (w->hscroll)
&& w->cursor.x <= h_margin)
|| (cursor_row->enabled_p
&& cursor_row->truncated_on_right_p
&& (w->cursor.x >= text_area_width - h_margin)))
{
struct it it;
int hscroll;
struct buffer *saved_current_buffer;
int pt;
int wanted_x;
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;
if (!hscroll_relative_p && hscroll_step_abs == 0)
hscroll = max (0, (it.current_x
- (ITERATOR_AT_END_OF_LINE_P (&it)
? (text_area_width - 4 * FRAME_COLUMN_WIDTH (it.f))
: (text_area_width / 2))))
/ FRAME_COLUMN_WIDTH (it.f);
else if (w->cursor.x >= text_area_width - h_margin)
{
if (hscroll_relative_p)
wanted_x = text_area_width * (1 - hscroll_step_rel)
- h_margin;
else
wanted_x = text_area_width
- hscroll_step_abs * FRAME_COLUMN_WIDTH (it.f)
- h_margin;
hscroll
= max (0, it.current_x - wanted_x) / FRAME_COLUMN_WIDTH (it.f);
}
else
{
if (hscroll_relative_p)
wanted_x = text_area_width * hscroll_step_rel
+ h_margin;
else
wanted_x = hscroll_step_abs * FRAME_COLUMN_WIDTH (it.f)
+ h_margin;
hscroll
= max (0, it.current_x - wanted_x) / FRAME_COLUMN_WIDTH (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;
EMACS_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 *) SDATA (XBUFFER (w->buffer)->name)
: "no buffer"),
buffer);
}
#endif
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);
}
static Lisp_Object
overlay_arrow_string_or_property (var)
Lisp_Object var;
{
Lisp_Object val;
if (val = Fget (var, Qoverlay_arrow_string), STRINGP (val))
return val;
return Voverlay_arrow_string;
}
static int
overlay_arrow_in_current_buffer_p ()
{
Lisp_Object vlist;
for (vlist = Voverlay_arrow_variable_list;
CONSP (vlist);
vlist = XCDR (vlist))
{
Lisp_Object var = XCAR (vlist);
Lisp_Object val;
if (!SYMBOLP (var))
continue;
val = find_symbol_value (var);
if (MARKERP (val)
&& current_buffer == XMARKER (val)->buffer)
return 1;
}
return 0;
}
static int
overlay_arrows_changed_p ()
{
Lisp_Object vlist;
for (vlist = Voverlay_arrow_variable_list;
CONSP (vlist);
vlist = XCDR (vlist))
{
Lisp_Object var = XCAR (vlist);
Lisp_Object val, pstr;
if (!SYMBOLP (var))
continue;
val = find_symbol_value (var);
if (!MARKERP (val))
continue;
if (! EQ (COERCE_MARKER (val),
Fget (var, Qlast_arrow_position))
|| ! (pstr = overlay_arrow_string_or_property (var),
EQ (pstr, Fget (var, Qlast_arrow_string))))
return 1;
}
return 0;
}
static void
update_overlay_arrows (up_to_date)
int up_to_date;
{
Lisp_Object vlist;
for (vlist = Voverlay_arrow_variable_list;
CONSP (vlist);
vlist = XCDR (vlist))
{
Lisp_Object var = XCAR (vlist);
if (!SYMBOLP (var))
continue;
if (up_to_date > 0)
{
Lisp_Object val = find_symbol_value (var);
Fput (var, Qlast_arrow_position,
COERCE_MARKER (val));
Fput (var, Qlast_arrow_string,
overlay_arrow_string_or_property (var));
}
else if (up_to_date < 0
|| !NILP (Fget (var, Qlast_arrow_position)))
{
Fput (var, Qlast_arrow_position, Qt);
Fput (var, Qlast_arrow_string, Qt);
}
}
}
static Lisp_Object
overlay_arrow_at_row (it, row)
struct it *it;
struct glyph_row *row;
{
Lisp_Object vlist;
for (vlist = Voverlay_arrow_variable_list;
CONSP (vlist);
vlist = XCDR (vlist))
{
Lisp_Object var = XCAR (vlist);
Lisp_Object val;
if (!SYMBOLP (var))
continue;
val = find_symbol_value (var);
if (MARKERP (val)
&& current_buffer == XMARKER (val)->buffer
&& (MATRIX_ROW_START_CHARPOS (row) == marker_position (val)))
{
if (FRAME_WINDOW_P (it->f)
&& WINDOW_LEFT_FRINGE_WIDTH (it->w) > 0)
{
#ifdef HAVE_WINDOW_SYSTEM
if (val = Fget (var, Qoverlay_arrow_bitmap), SYMBOLP (val))
{
int fringe_bitmap;
if ((fringe_bitmap = lookup_fringe_bitmap (val)) != 0)
return make_number (fringe_bitmap);
}
#endif
return make_number (-1);
}
return overlay_arrow_string_or_property (var);
}
}
return Qnil;
}
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->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
select_frame_for_redisplay (frame)
Lisp_Object frame;
{
Lisp_Object tail, sym, val;
Lisp_Object old = selected_frame;
selected_frame = frame;
for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail))
if (CONSP (XCAR (tail))
&& (sym = XCAR (XCAR (tail)),
SYMBOLP (sym))
&& (sym = indirect_variable (sym),
val = SYMBOL_VALUE (sym),
(BUFFER_LOCAL_VALUEP (val)
|| SOME_BUFFER_LOCAL_VALUEP (val)))
&& XBUFFER_LOCAL_VALUE (val)->check_frame)
find_symbol_value (sym);
for (tail = XFRAME (old)->param_alist; CONSP (tail); tail = XCDR (tail))
if (CONSP (XCAR (tail))
&& (sym = XCAR (XCAR (tail)),
SYMBOLP (sym))
&& (sym = indirect_variable (sym),
val = SYMBOL_VALUE (sym),
(BUFFER_LOCAL_VALUEP (val)
|| SOME_BUFFER_LOCAL_VALUEP (val)))
&& XBUFFER_LOCAL_VALUE (val)->check_frame)
find_symbol_value (sym);
}
#define STOP_POLLING \
do { if (! polling_stopped_here) stop_polling (); \
polling_stopped_here = 1; } while (0)
#define RESUME_POLLING \
do { if (polling_stopped_here) start_polling (); \
polling_stopped_here = 0; } while (0)
static void
redisplay_internal (preserve_echo_area)
int preserve_echo_area;
{
struct window *w = XWINDOW (selected_window);
struct frame *f;
int pause;
int must_finish = 0;
struct text_pos tlbufpos, tlendpos;
int number_of_visible_frames;
int count, count1;
struct frame *sf;
int polling_stopped_here = 0;
int consider_all_windows_p;
TRACE ((stderr, "redisplay_internal %d\n", redisplaying_p));
if (noninteractive
|| !NILP (Vinhibit_redisplay))
return;
f = XFRAME (w->frame);
sf = SELECTED_FRAME ();
if (!f->glyphs_initialized_p)
return;
if (redisplay_performed_directly_p)
{
redisplay_performed_directly_p = 0;
if (!hscroll_windows (selected_window))
return;
}
#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (MAC_OS)
if (popup_activated ())
return;
#endif
if (redisplaying_p)
return;
count = SPECPDL_INDEX ();
record_unwind_protect (unwind_redisplay,
Fcons (make_number (redisplaying_p), selected_frame));
++redisplaying_p;
specbind (Qinhibit_free_realized_faces, Qnil);
{
Lisp_Object tail, frame;
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
f->already_hscrolled_p = 0;
}
}
retry:
pause = 0;
reconsider_clip_changes (w, current_buffer);
last_escape_glyph_frame = NULL;
last_escape_glyph_face_id = (1 << FACE_ID_BITS);
if (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 ();
if (NILP (Vmemory_full))
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++;
}
count1 = SPECPDL_INDEX ();
specbind (Qinhibit_point_motion_hooks, Qt);
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)
!= (int) current_column ()))
w->update_mode_line = Qt;
unbind_to (count1, Qnil);
FRAME_SCROLL_BOTTOM_VPOS (XFRAME (w->frame)) = -1;
consider_all_windows_p = (update_mode_lines || buffer_shared > 1
|| cursor_type_changed);
if (overlay_arrows_changed_p ())
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
&& !current_buffer->prevent_redisplay_optimizations_p
&& 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)
&& NILP (w->optional_new_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
#ifdef HAVE_WINDOW_SYSTEM
update_window_fringes (w, 0);
#endif
goto update;
}
else
goto cancel;
}
else if (
PT == XFASTINT (w->last_point)
&& 0 <= w->cursor.vpos
&& WINDOW_TOTAL_LINES (w) > 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;
#ifdef HAVE_WINDOW_SYSTEM
++clear_image_cache_count;
#endif
if (consider_all_windows_p)
{
Lisp_Object tail, frame;
FOR_EACH_FRAME (tail, frame)
XFRAME (frame)->updated_p = 0;
buffer_shared = 0;
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
if (FRAME_WINDOW_P (f) || f == sf)
{
if (! EQ (frame, selected_frame))
select_frame_for_redisplay (frame);
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 (!f->already_hscrolled_p)
{
f->already_hscrolled_p = 1;
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 0
if (pause)
break;
#endif
f->updated_p = 1;
}
}
}
if (!pause)
{
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
if (f->updated_p)
{
mark_window_display_accurate (f->root_window, 1);
if (frame_up_to_date_hook)
frame_up_to_date_hook (f);
}
}
}
}
else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
{
Lisp_Object mini_window;
struct frame *mini_frame;
displayed_buffer = XBUFFER (XWINDOW (selected_window)->buffer);
internal_condition_case_1 (redisplay_window_1, selected_window,
list_of_error,
redisplay_window_error);
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;
update_overlay_arrows (0);
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);
update_overlay_arrows (1);
if (frame_up_to_date_hook != 0)
frame_up_to_date_hook (sf);
}
update_mode_lines = 0;
windows_or_buffers_changed = 0;
cursor_type_changed = 0;
}
if (interrupt_input)
request_sigio ();
RESUME_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;
if (consider_all_windows_p)
{
if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT)
{
clear_face_cache (0);
clear_face_cache_count = 0;
}
#ifdef HAVE_WINDOW_SYSTEM
if (clear_image_cache_count > CLEAR_IMAGE_CACHE_COUNT)
{
Lisp_Object tail, frame;
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
if (FRAME_WINDOW_P (f))
clear_image_cache (f, 0);
}
clear_image_cache_count = 0;
}
#endif
}
end_of_redisplay:
unbind_to (count, Qnil);
RESUME_POLLING;
}
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);
if (rif != NULL && rif->flush_display_optional)
rif->flush_display_optional (NULL);
}
static Lisp_Object
unwind_redisplay (val)
Lisp_Object val;
{
Lisp_Object old_redisplaying_p, old_frame;
old_redisplaying_p = XCAR (val);
redisplaying_p = XFASTINT (old_redisplaying_p);
old_frame = XCDR (val);
if (! EQ (old_frame, selected_frame))
select_frame_for_redisplay (old_frame);
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)
< (WINDOW_TOTAL_LINES (w)
- (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)
{
update_overlay_arrows (1);
}
else
{
update_overlay_arrows (-1);
}
}
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
{
displayed_buffer = XBUFFER (w->buffer);
internal_condition_case_1 (redisplay_window_0, window,
list_of_error,
redisplay_window_error);
}
window = w->next;
}
}
static Lisp_Object
redisplay_window_error ()
{
displayed_buffer->display_error_modiff = BUF_MODIFF (displayed_buffer);
return Qnil;
}
static Lisp_Object
redisplay_window_0 (window)
Lisp_Object window;
{
if (displayed_buffer->display_error_modiff < BUF_MODIFF (displayed_buffer))
redisplay_window (window, 0);
return Qnil;
}
static Lisp_Object
redisplay_window_1 (window)
Lisp_Object window;
{
if (displayed_buffer->display_error_modiff < BUF_MODIFF (displayed_buffer))
redisplay_window (window, 1);
return Qnil;
}
#define SKIP_GLYPHS(glyph, end, x, condition) \
do \
{ \
(x) += (glyph)->pixel_width; \
++(glyph); \
} \
while ((glyph) < (end) && (condition))
int
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];
struct glyph *cursor = NULL;
struct glyph *string_start;
int string_start_x;
int last_pos = MATRIX_ROW_START_CHARPOS (row) + delta;
int string_before_pos;
int x = row->x;
int cursor_x = x;
int cursor_from_overlay_pos = 0;
int pt_old = PT - delta;
if (row->displays_text_p)
while (glyph < end
&& INTEGERP (glyph->object)
&& glyph->charpos < 0)
{
x += glyph->pixel_width;
++glyph;
}
string_start = NULL;
while (glyph < end
&& !INTEGERP (glyph->object)
&& (!BUFFERP (glyph->object)
|| (last_pos = glyph->charpos) < pt_old))
{
if (! STRINGP (glyph->object))
{
string_start = NULL;
x += glyph->pixel_width;
++glyph;
if (cursor_from_overlay_pos
&& last_pos >= cursor_from_overlay_pos)
{
cursor_from_overlay_pos = 0;
cursor = 0;
}
}
else
{
if (string_start == NULL)
{
string_before_pos = last_pos;
string_start = glyph;
string_start_x = x;
}
do
{
Lisp_Object cprop;
int pos;
if ((cursor == NULL || glyph > cursor)
&& (cprop = Fget_char_property (make_number ((glyph)->charpos),
Qcursor, (glyph)->object),
!NILP (cprop))
&& (pos = string_buffer_position (w, glyph->object,
string_before_pos),
(pos == 0
|| pos == pt_old)))
{
cursor_from_overlay_pos = (pos ? 0 : last_pos
+ (INTEGERP (cprop) ? XINT (cprop) : 0));
cursor = glyph;
cursor_x = x;
}
x += glyph->pixel_width;
++glyph;
}
while (glyph < end && EQ (glyph->object, string_start->object));
}
}
if (cursor != NULL)
{
glyph = cursor;
x = cursor_x;
}
else if (row->ends_in_ellipsis_p && glyph == end)
{
while (glyph > row->glyphs[TEXT_AREA]
&& (glyph - 1)->charpos == last_pos)
glyph--, x -= glyph->pixel_width;
x += glyph->pixel_width;
glyph++;
}
else if (string_start
&& (glyph == end || !BUFFERP (glyph->object) || last_pos > pt_old))
{
Lisp_Object limit;
Lisp_Object string;
struct glyph *stop = glyph;
int pos;
limit = make_number (pt_old + 1);
glyph = string_start;
x = string_start_x;
string = glyph->object;
pos = string_buffer_position (w, string, string_before_pos);
while (pos == 0 && glyph < stop)
{
string = glyph->object;
SKIP_GLYPHS (glyph, stop, x, EQ (glyph->object, string));
if (glyph < stop)
pos = string_buffer_position (w, glyph->object, string_before_pos);
}
while (glyph < stop)
{
pos = XINT (Fnext_single_char_property_change
(make_number (pos), Qdisplay, Qnil, limit));
if (pos > pt_old)
break;
string = glyph->object;
SKIP_GLYPHS (glyph, stop, x, EQ (glyph->object, string));
while (glyph < stop
&& ! string_buffer_position (w, glyph->object, pos))
{
string = glyph->object;
SKIP_GLYPHS (glyph, stop, x, EQ (glyph->object, string));
}
}
if (glyph == end && row->continued_p)
return 0;
}
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;
}
return 1;
}
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
cursor_row_fully_visible_p (w, force_p, current_matrix_p)
struct window *w;
int force_p;
int current_matrix_p;
{
struct glyph_matrix *matrix;
struct glyph_row *row;
int window_height;
if (!make_cursor_line_fully_visible_p)
return 1;
if (w->cursor.vpos < 0)
return 1;
matrix = current_matrix_p ? w->current_matrix : w->desired_matrix;
row = MATRIX_ROW (matrix, w->cursor.vpos);
if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (w, row))
return 1;
window_height = window_box_height (w);
if (row->height >= window_height)
{
if (!force_p || MINI_WINDOW_P (w)
|| w->vscroll || w->cursor.vpos == 0)
return 1;
}
return 0;
#if 0
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;
#endif
}
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, last_line_misfit)
Lisp_Object window;
int just_this_one_p;
EMACS_INT scroll_conservatively, scroll_step;
int temp_scroll_step;
int last_line_misfit;
{
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;
int extra_scroll_margin_lines = last_line_misfit ? 1 : 0;
#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, WINDOW_TOTAL_LINES (w) / 4);
this_scroll_margin *= FRAME_LINE_HEIGHT (f);
}
else
this_scroll_margin = 0;
if (scroll_conservatively)
scroll_conservatively = min (scroll_conservatively,
MOST_POSITIVE_FIXNUM / FRAME_LINE_HEIGHT (f));
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 *= FRAME_LINE_HEIGHT (f);
window_end = Fwindow_end (window, Qt);
too_near_end:
CHARPOS (scroll_margin_pos) = XINT (window_end);
BYTEPOS (scroll_margin_pos) = CHAR_TO_BYTE (CHARPOS (scroll_margin_pos));
if (this_scroll_margin || extra_scroll_margin_lines)
{
start_display (&it, w, scroll_margin_pos);
if (this_scroll_margin)
move_it_vertically_backward (&it, this_scroll_margin);
if (extra_scroll_margin_lines)
move_it_by_lines (&it, - extra_scroll_margin_lines, 0);
scroll_margin_pos = it.current.pos;
}
if (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
= min (max (dy, FRAME_LINE_HEIGHT (f)),
FRAME_LINE_HEIGHT (f) * scroll_conservatively);
else if (scroll_step || temp_scroll_step)
amount_to_scroll = scroll_max;
else
{
aggressive = current_buffer->scroll_up_aggressively;
height = WINDOW_BOX_TEXT_HEIGHT (w);
if (NUMBERP (aggressive))
{
double float_amount = XFLOATINT (aggressive) * height;
amount_to_scroll = float_amount;
if (amount_to_scroll == 0 && float_amount > 0)
amount_to_scroll = 1;
}
}
if (amount_to_scroll <= 0)
return SCROLLING_FAILED;
move_it_vertically (&it, amount_to_scroll);
if (CHARPOS (it.current.pos) == CHARPOS (startp))
move_it_by_lines (&it, 1, 1);
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, FRAME_LINE_HEIGHT (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_BOX_TEXT_HEIGHT (w);
if (NUMBERP (aggressive))
{
double float_amount = XFLOATINT (aggressive) * height;
amount_to_scroll = float_amount;
if (amount_to_scroll == 0 && float_amount > 0)
amount_to_scroll = 1;
}
}
if (amount_to_scroll <= 0)
return SCROLLING_FAILED;
move_it_vertically_backward (&it, amount_to_scroll);
startp = it.current.pos;
}
}
startp = run_window_scroll_functions (window, startp);
if (!try_window (window, startp, 0))
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 (! cursor_row_fully_visible_p (w, extra_scroll_margin_lines <= 1, 0))
{
clear_glyph_matrix (w->desired_matrix);
++extra_scroll_margin_lines;
goto too_near_end;
}
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)
< WINDOW_TOTAL_LINES (w) * WINDOW_TOTAL_COLS (w))
{
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
&& !cursor_type_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)
|| !overlay_arrow_in_current_buffer_p ()))
{
int this_scroll_margin, top_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, WINDOW_TOTAL_LINES (w) / 4);
this_scroll_margin *= FRAME_LINE_HEIGHT (f);
top_scroll_margin = this_scroll_margin;
if (WINDOW_WANTS_HEADER_LINE_P (w))
top_scroll_margin += CURRENT_HEADER_LINE_HEIGHT (w);
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 > w->current_matrix->rows
&& (row-1)->ends_in_newline_from_string_p))))
&& (row->y > top_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 < top_scroll_margin
&& CHARPOS (startp) != BEGV)
scroll_p = 1;
}
else
{
rc = CURSOR_MOVEMENT_SUCCESS;
}
if (PT < MATRIX_ROW_START_CHARPOS (row)
|| PT > MATRIX_ROW_END_CHARPOS (row))
{
rc = CURSOR_MOVEMENT_MUST_SCROLL;
}
else if (rc != CURSOR_MOVEMENT_SUCCESS
&& MATRIX_ROW_PARTIALLY_VISIBLE_P (w, row)
&& make_cursor_line_fully_visible_p)
{
if (PT == MATRIX_ROW_END_CHARPOS (row)
&& !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);
if (!cursor_row_fully_visible_p (w, 0, 1))
rc = CURSOR_MOVEMENT_MUST_SCROLL;
else
rc = CURSOR_MOVEMENT_SUCCESS;
}
}
else if (scroll_p)
rc = CURSOR_MOVEMENT_MUST_SCROLL;
else
{
do
{
if (set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0))
{
rc = CURSOR_MOVEMENT_SUCCESS;
break;
}
++row;
}
while (MATRIX_ROW_BOTTOM_Y (row) < last_y
&& MATRIX_ROW_START_CHARPOS (row) == PT
&& cursor_row_p (w, row));
}
}
}
return rc;
}
void
set_vertical_scroll_bar (w)
struct window *w;
{
int start, end, whole;
if (!MINI_WINDOW_P (w)
|| (w == XWINDOW (minibuf_window)
&& NILP (echo_area_buffer[0])))
{
struct buffer *buf = XBUFFER (w->buffer);
whole = BUF_ZV (buf) - BUF_BEGV (buf);
start = marker_position (w->start) - BUF_BEGV (buf);
end = BUF_Z (buf) - XFASTINT (w->window_end_pos) - BUF_BEGV (buf);
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);
}
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 used_current_matrix_p = 0;
int buffer_unchanged_p = 0;
int temp_scroll_step = 0;
int count = SPECPDL_INDEX ();
int rc;
int centering_position = -1;
int last_line_misfit = 0;
int save_beg_unchanged, save_end_unchanged;
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
|| buffer->prevent_redisplay_optimizations_p);
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)
|| minibuf_level == 0)
&& BUF_Z (XBUFFER (w->buffer)) == BUF_BEG (XBUFFER (w->buffer))
&& !NILP (Fmemq (w->buffer, Vminibuffer_list)))
{
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);
save_beg_unchanged = BEG_UNCHANGED;
save_end_unchanged = END_UNCHANGED;
current_matrix_up_to_date_p
= (!NILP (w->window_end_valid)
&& !current_buffer->clip_changed
&& !current_buffer->prevent_redisplay_optimizations_p
&& XFASTINT (w->last_modified) >= MODIFF
&& XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF);
buffer_unchanged_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)
!= (int) 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;
else if (IT_CHARPOS (it) > PT && CHARPOS (startp) <= PT)
w->force_start = Qt;
}
force_start:
if (!NILP (w->force_start)
|| w->frozen_window_start_p)
{
int new_vpos = -1;
int val;
w->force_start = Qnil;
w->vscroll = 0;
w->window_end_valid = Qnil;
if (!buffer_unchanged_p)
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);
val = try_window (window, startp, 1);
if (!val)
{
w->force_start = Qt;
clear_glyph_matrix (w->desired_matrix);
goto need_larger_matrices;
}
if (val < 0)
new_vpos = window_box_height (w) / 2;
if (w->cursor.vpos < 0 && !w->frozen_window_start_p)
{
new_vpos = window_box_height (w) / 2;
}
if (!cursor_row_fully_visible_p (w, 0, 0))
{
new_vpos = window_box_height (w);
}
if (new_vpos >= 0)
{
struct glyph_row *row;
row = MATRIX_FIRST_TEXT_ROW (w->desired_matrix);
while (MATRIX_ROW_BOTTOM_Y (row) < new_vpos)
++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, 0))
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:
used_current_matrix_p = 1;
goto done;
#if 0
case CURSOR_MOVEMENT_NEED_LARGER_MATRICES:
goto need_larger_matrices;
#endif
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 (NILP (w->start_at_line_beg)
&& NILP (do_mouse_tracking)
&& CHARPOS (startp) > BEGV
&& CHARPOS (startp) > BEG + save_beg_unchanged
&& CHARPOS (startp) <= Z - save_end_unchanged)
{
w->force_start = Qt;
if (XMARKER (w->start)->buffer == current_buffer)
compute_window_start_on_continuation_line (w);
SET_TEXT_POS_FROM_MARKER (startp, w->start);
goto force_start;
}
#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)
|| !(used_current_matrix_p
= try_window_reusing_current_matrix (w)))
{
IF_DEBUG (debug_method_add (w, "1"));
if (try_window (window, startp, 1) < 0)
goto try_to_scroll;
}
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 (!cursor_row_fully_visible_p (w, 1, 0))
{
clear_glyph_matrix (w->desired_matrix);
last_line_misfit = 1;
}
else
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, last_line_misfit);
switch (rc)
{
case SCROLLING_SUCCESS:
goto done;
case SCROLLING_NEED_LARGER_MATRICES:
goto need_larger_matrices;
case SCROLLING_FAILED:
break;
default:
abort ();
}
}
recenter:
if (centering_position < 0)
centering_position = window_box_height (w) / 2;
#if GLYPH_DEBUG
debug_method_add (w, "recenter");
#endif
if (!buffer_unchanged_p)
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, centering_position);
xassert (IT_CHARPOS (it) >= BEGV);
if (it.current_y <= 0)
{
init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
move_it_vertically_backward (&it, 0);
#if 0
xassert (IT_CHARPOS (it) <= PT);
#endif
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
|| cursor_type_changed
|| !NILP (Vwindow_scroll_functions)
|| !just_this_one_p
|| MINI_WINDOW_P (w)
|| !(used_current_matrix_p
= try_window_reusing_current_matrix (w)))
try_window (window, startp, 0);
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, 0);
}
else if (PT < IT_CHARPOS (it))
{
clear_glyph_matrix (w->desired_matrix);
move_it_by_lines (&it, -1, 0);
try_window (window, it.current.pos, 0);
}
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 (!cursor_row_fully_visible_p (w, 0, 0))
{
if (w->vscroll)
{
w->vscroll = 0;
clear_glyph_matrix (w->desired_matrix);
goto recenter;
}
if (centering_position == 0)
goto done;
clear_glyph_matrix (w->desired_matrix);
centering_position = 0;
goto recenter;
}
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)
!= (int) 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;
int redisplay_tool_bar_p = 0;
if (FRAME_WINDOW_P (f))
{
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
|| defined (USE_GTK)
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
#ifdef USE_GTK
redisplay_tool_bar_p = FRAME_EXTERNAL_TOOL_BAR (f);
#else
redisplay_tool_bar_p = WINDOWP (f->tool_bar_window)
&& (FRAME_TOOL_BAR_LINES (f) > 0
|| !NILP (Vauto_resize_tool_bars));
#endif
if (redisplay_tool_bar_p && redisplay_tool_bar (f))
{
extern int ignore_mouse_drag_p;
ignore_mouse_drag_p = 1;
}
#endif
}
#ifdef HAVE_WINDOW_SYSTEM
if (FRAME_WINDOW_P (f)
&& update_window_fringes (w, (just_this_one_p
|| (!used_current_matrix_p && !overlay_arrow_seen)
|| w->pseudo_window_p)))
{
update_begin (f);
BLOCK_INPUT;
if (draw_window_fringes (w, 1))
x_draw_vertical_border (w);
UNBLOCK_INPUT;
update_end (f);
}
#endif
need_larger_matrices:
;
finish_scroll_bars:
if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
{
set_vertical_scroll_bar (w);
redeem_scroll_bar_hook (w);
}
TEMP_SET_PT_BOTH (CHARPOS (opoint), BYTEPOS (opoint));
set_buffer_internal_1 (old);
if (CHARPOS (lpoint) <= ZV)
TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
unbind_to (count, Qnil);
}
int
try_window (window, pos, check_margins)
Lisp_Object window;
struct text_pos pos;
int check_margins;
{
struct window *w = XWINDOW (window);
struct it it;
struct glyph_row *last_text_row = NULL;
struct frame *f = XFRAME (w->frame);
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 (check_margins
&& !MINI_WINDOW_P (w))
{
int this_scroll_margin;
this_scroll_margin = max (0, scroll_margin);
this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
if ((w->cursor.y >= 0
&& w->cursor.y < this_scroll_margin
&& CHARPOS (pos) > BEGV
&& IT_CHARPOS (it) < ZV)
|| (w->cursor.y + 1) > it.last_visible_y)
{
w->cursor.vpos = -1;
clear_glyph_matrix (w->desired_matrix);
return -1;
}
}
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 = Z_BYTE - ZV_BYTE;
w->window_end_pos = make_number (Z - ZV);
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
|| cursor_type_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 (w, 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
&& !fonts_changed_p)
{
while (IT_CHARPOS (it) > CHARPOS (start))
{
start_row++;
start = start_row->start.pos;
if (start_row == MATRIX_MODE_LINE_ROW (w->current_matrix) - 1
|| w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (w, start_row)
|| CHARPOS (start) == ZV)
{
clear_glyph_matrix (w->desired_matrix);
return 0;
}
start_vpos = MATRIX_ROW_VPOS (start_row, w->current_matrix);
}
if (IT_CHARPOS (it) == CHARPOS (start))
break;
if (display_line (&it))
last_text_row = it.glyph_row - 1;
}
if (it.current_y < it.last_visible_y)
{
nrows_scrolled = it.vpos - (start_row - MATRIX_FIRST_TEXT_ROW (w->current_matrix));
if (w->cursor.vpos < 0)
{
int dy = it.current_y - start_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 = start_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_window_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 < nrows_scrolled; ++i)
(start_row + i)->enabled_p = 0;
min_y = WINDOW_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;
row->redraw_fringe_bitmaps_p = 1;
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 = row->mode_line_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 = Z_BYTE - ZV_BYTE;
w->window_end_pos = make_number (Z - ZV);
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_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 -= nrows_scrolled;
w->cursor.y -= first_reusable_row->y - start_row->y;
}
run.current_y = first_reusable_row->y;
run.desired_y = WINDOW_HEADER_LINE_HEIGHT (w);
run.height = it.last_visible_y - run.current_y;
dy = run.current_y - run.desired_y;
if (run.height)
{
update_begin (f);
rif->update_window_begin_hook (w);
rif->clear_window_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_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;
row->redraw_fringe_bitmaps_p = 1;
}
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 (pt_row)
{
for (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
row < bottom_row && PT >= MATRIX_ROW_END_CHARPOS (row);
row++)
{
w->cursor.vpos++;
w->cursor.y = row->y;
}
if (row < bottom_row)
{
struct glyph *glyph = row->glyphs[TEXT_AREA] + w->cursor.hpos;
while (glyph->charpos < PT)
{
w->cursor.hpos++;
w->cursor.x += glyph->pixel_width;
glyph++;
}
}
}
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->exact_window_width_line_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))
break;
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 + WINDOW_TOP_EDGE_LINE (w);
while (window_row < window_row_end)
{
struct glyph *start = window_row->glyphs[LEFT_MARGIN_AREA];
struct glyph *end = window_row->glyphs[LAST_AREA];
frame_row->glyphs[LEFT_MARGIN_AREA] = start;
frame_row->glyphs[TEXT_AREA] = start;
frame_row->glyphs[RIGHT_MARGIN_AREA] = end;
frame_row->glyphs[LAST_AREA] = end;
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 (1)
{
if (end && row >= end)
return NULL;
if (MATRIX_ROW_BOTTOM_Y (row) > last_y)
return NULL;
if (! (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)))
&& charpos >= MATRIX_ROW_START_CHARPOS (row))
return row;
++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 || cursor_type_changed)
GIVE_UP (2);
if (current_buffer->clip_changed
|| current_buffer->prevent_redisplay_optimizations_p)
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 (overlay_arrows_changed_p ())
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
&& !(PT >= MATRIX_ROW_START_CHARPOS (row) + delta
&& MATRIX_ROW_BOTTOM_Y (row) > window_text_bottom_y (w)))
{
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);
if (row)
set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0);
else
abort ();
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)
&& !(PT >= MATRIX_ROW_START_CHARPOS (row)
&& MATRIX_ROW_BOTTOM_Y (row) > window_text_bottom_y (w)))
{
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);
if (row)
set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0);
else
abort ();
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);
it.vpos = it.first_vpos;
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)
{
xassert (last_unchanged_at_beg_row == NULL
|| first_unchanged_at_end_row >= last_unchanged_at_beg_row);
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, WINDOW_TOTAL_LINES (w) / 4);
this_scroll_margin *= FRAME_LINE_HEIGHT (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 + (make_cursor_line_fully_visible_p
? cursor_height + this_scroll_margin
: 1)) > 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_window_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 = WINDOW_TOP_EDGE_LINE (w) + first_unchanged_at_end_vpos;
int end = (WINDOW_TOP_EDGE_LINE (w)
+ (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 || delta_bytes)
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;
if (first_unchanged_at_end_row->y >= it.last_visible_y
|| !MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row))
first_unchanged_at_end_row = NULL;
}
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
&& !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);
}
else if (glyph->type == COMPOSITE_GLYPH)
{
fprintf (stderr,
" %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
glyph - row->glyphs[TEXT_AREA],
'+',
glyph->charpos,
(BUFFERP (glyph->object)
? 'B'
: (STRINGP (glyph->object)
? 'S'
: '-')),
glyph->pixel_width,
glyph->u.cmp_id,
'.',
glyph->face_id,
glyph->left_box_line_p,
glyph->right_box_line_p);
}
}
void
dump_glyph_row (row, vpos, glyphs)
struct glyph_row *row;
int vpos, glyphs;
{
if (glyphs != 1)
{
fprintf (stderr, "Row Start End Used oE><\\CTZFesm X Y W H V A P\n");
fprintf (stderr, "======================================================================\n");
fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d\
%1.1d%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->truncated_on_left_p,
row->truncated_on_right_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",
doc: )
(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-frame-glyph-matrix", Fdump_frame_glyph_matrix,
Sdump_frame_glyph_matrix, 0, 0, "", doc: )
()
{
struct frame *f = XFRAME (selected_frame);
dump_glyph_matrix (f->current_matrix, 1);
return Qnil;
}
DEFUN ("dump-glyph-row", Fdump_glyph_row, Sdump_glyph_row, 1, 2, "",
doc: )
(row, glyphs)
Lisp_Object row, glyphs;
{
struct glyph_matrix *matrix;
int vpos;
CHECK_NUMBER (row);
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, "",
doc: )
(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);
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",
doc: )
(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, "",
doc: )
(nargs, args)
int nargs;
Lisp_Object *args;
{
Lisp_Object s = Fformat (nargs, args);
fprintf (stderr, "%s", SDATA (s));
return Qnil;
}
#endif
static struct glyph_row *
get_overlay_arrow_glyph_row (w, overlay_arrow_string)
struct window *w;
Lisp_Object overlay_arrow_string;
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
struct buffer *buffer = XBUFFER (w->buffer);
struct buffer *old = current_buffer;
const unsigned char *arrow_string = SDATA (overlay_arrow_string);
int arrow_len = SCHARS (overlay_arrow_string);
const unsigned char *arrow_end = arrow_string + arrow_len;
const 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, overlay_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 = FRAME_LINE_HEIGHT (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->extra_line_spacing = it->max_extra_line_spacing;
}
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_HEADER_LINE_HEIGHT (it->w);
max_y = WINDOW_BOX_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->extra_line_spacing = 0;
}
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_for_newline (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->override_ascent = -1;
it->constrain_row_ascent_descent_p = 0;
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)
&& it->glyph_row->displays_text_p
&& 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, 0);
if (face_id < 0)
return;
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)
{
if (row->continued_p)
cursor_row_p = 1;
else
{
struct glyph *beg = row->glyphs[TEXT_AREA];
struct glyph *end = beg + row->used[TEXT_AREA] - 1;
struct glyph *glyph;
cursor_row_p = 0;
for (glyph = end; glyph >= beg; --glyph)
if (STRINGP (glyph->object))
{
Lisp_Object prop
= Fget_char_property (make_number (PT),
Qdisplay, Qnil);
cursor_row_p =
(!NILP (prop)
&& display_prop_string_p (prop, glyph->object));
break;
}
}
}
else if (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
{
if (!row->ends_in_ellipsis_p)
cursor_row_p = row->continued_p;
else
cursor_row_p = 0;
}
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;
Lisp_Object overlay_arrow_string;
xassert (it->hpos == 0 && it->current_x == 0);
if (MATRIX_ROW_VPOS (row, it->w->desired_matrix)
>= it->w->desired_matrix->nrows)
{
it->w->nrows_scale_factor++;
fonts_changed_p = 1;
return 0;
}
it->w->region_showing = it->region_beg_charpos > 0 ? Qt : Qnil;
prepare_desired_row (row);
row->y = it->current_y;
row->start = it->start;
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;
row->extra_line_spacing = it->max_extra_line_spacing;
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))
{
#ifdef HAVE_WINDOW_SYSTEM
if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
row->exact_window_width_line_p = 1;
else
#endif
if ((append_space_for_newline (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);
row->extra_line_spacing = max (row->extra_line_spacing,
it->max_extra_line_spacing);
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);
row->extra_line_spacing = max (row->extra_line_spacing,
it->max_extra_line_spacing);
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);
#ifdef HAVE_WINDOW_SYSTEM
if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
{
if (!get_next_display_element (it))
{
row->exact_window_width_line_p = 1;
it->continuation_lines_width = 0;
row->continued_p = 0;
row->ends_at_zv_p = 1;
}
else if (ITERATOR_AT_END_OF_LINE_P (it))
{
row->continued_p = 0;
row->exact_window_width_line_p = 1;
}
}
#endif
}
}
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->current_x = x_before;
it->continuation_lines_width += x;
extend_face_to_end_of_line (it);
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
{
xassert (it->first_visible_x <= it->last_visible_x);
}
}
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);
row->extra_line_spacing = max (row->extra_line_spacing,
it->max_extra_line_spacing);
if (row->continued_p || row->ends_at_zv_p)
break;
}
at_end_of_line:
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);
#ifdef HAVE_WINDOW_SYSTEM
if (!IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
append_space_for_newline (it, 0);
#endif
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);
}
}
#ifdef HAVE_WINDOW_SYSTEM
else
{
if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
{
if (!get_next_display_element (it))
{
it->continuation_lines_width = 0;
row->ends_at_zv_p = 1;
row->exact_window_width_line_p = 1;
break;
}
if (ITERATOR_AT_END_OF_LINE_P (it))
{
row->exact_window_width_line_p = 1;
goto at_end_of_line;
}
}
}
#endif
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 ((row->displays_text_p || !overlay_arrow_seen)
&& (overlay_arrow_string = overlay_arrow_at_row (it, row),
!NILP (overlay_arrow_string)))
{
if (STRINGP (overlay_arrow_string))
{
struct glyph_row *arrow_row
= get_overlay_arrow_glyph_row (it->w, overlay_arrow_string);
struct glyph *glyph = arrow_row->glyphs[TEXT_AREA];
struct glyph *arrow_end = glyph + arrow_row->used[TEXT_AREA];
struct glyph *p = row->glyphs[TEXT_AREA];
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];
}
}
else
{
xassert (INTEGERP (overlay_arrow_string));
row->overlay_arrow_bitmap = XINT (overlay_arrow_string);
}
overlay_arrow_seen = 1;
}
compute_line_metrics (it);
row->end = it->current;
row->ends_in_ellipsis_p
= (it->method == GET_FROM_DISPLAY_VECTOR
&& it->ellipsis_p);
row->left_user_fringe_bitmap = it->left_user_fringe_bitmap;
row->left_user_fringe_face_id = it->left_user_fringe_face_id;
row->right_user_fringe_bitmap = it->right_user_fringe_bitmap;
row->right_user_fringe_face_id = it->right_user_fringe_face_id;
it->left_user_fringe_bitmap = 0;
it->left_user_fringe_face_id = 0;
it->right_user_fringe_bitmap = 0;
it->right_user_fringe_face_id = 0;
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;
it->start = it->current;
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
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
if (FRAME_X_P (f))
return;
#endif
#ifdef MAC_OS
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_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (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_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (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_COLS (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,
SCHARS (string) + 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))
{
struct window *sel_w = XWINDOW (old_selected_window);
display_mode_line (w, CURRENT_MODE_LINE_FACE_ID_3 (sel_w, sel_w, w),
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;
int count = SPECPDL_INDEX ();
init_iterator (&it, w, -1, -1, NULL, face_id);
it.glyph_row->enabled_p = 0;
prepare_desired_row (it.glyph_row);
it.glyph_row->mode_line_p = 1;
if (! mode_line_inverse_video)
it.base_face_id = it.face_id = DEFAULT_FACE_ID;
record_unwind_protect (unwind_format_mode_line,
format_mode_line_unwind_data (NULL, 0));
mode_line_target = MODE_LINE_DISPLAY;
push_frame_kboard (it.f);
record_unwind_save_match_data ();
display_mode_element (&it, 0, 0, 0, format, Qnil, 0);
pop_frame_kboard ();
unbind_to (count, Qnil);
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->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 Lisp_Object
move_elt_to_front (elt, list)
Lisp_Object elt, list;
{
register Lisp_Object tail, prev;
register Lisp_Object tem;
tail = list;
prev = Qnil;
while (CONSP (tail))
{
tem = XCAR (tail);
if (EQ (elt, tem))
{
if (NILP (prev))
list = XCDR (tail);
else
Fsetcdr (prev, XCDR (tail));
Fsetcdr (tail, list);
return tail;
}
else
prev = tail;
tail = XCDR (tail);
QUIT;
}
return list;
}
static int
display_mode_element (it, depth, field_width, precision, elt, props, risky)
struct it *it;
int depth;
int field_width, precision;
Lisp_Object elt, props;
int risky;
{
int n = 0, field, prec;
int literal = 0;
tail_recurse:
if (depth > 100)
elt = build_string ("*too-deep*");
depth++;
switch (SWITCH_ENUM_CAST (XTYPE (elt)))
{
case Lisp_String:
{
unsigned char c;
int offset = 0;
if (SCHARS (elt) > 0
&& (!NILP (props) || risky))
{
Lisp_Object oprops, aelt;
oprops = Ftext_properties_at (make_number (0), elt);
if (NILP (Fequal (props, oprops)) || risky)
{
if (! NILP (oprops) && !risky)
{
Lisp_Object tem;
oprops = Fcopy_sequence (oprops);
tem = props;
while (CONSP (tem))
{
oprops = Fplist_put (oprops, XCAR (tem),
XCAR (XCDR (tem)));
tem = XCDR (XCDR (tem));
}
props = oprops;
}
aelt = Fassoc (elt, mode_line_proptrans_alist);
if (! NILP (aelt) && !NILP (Fequal (props, XCDR (aelt))))
{
elt = XCAR (aelt);
mode_line_proptrans_alist
= move_elt_to_front (aelt, mode_line_proptrans_alist);
}
else
{
Lisp_Object tem;
if (! NILP (aelt))
mode_line_proptrans_alist
= Fdelq (aelt, mode_line_proptrans_alist);
elt = Fcopy_sequence (elt);
Fset_text_properties (make_number (0), Flength (elt),
props, elt);
mode_line_proptrans_alist
= Fcons (Fcons (elt, props),
mode_line_proptrans_alist);
tem = Fnthcdr (make_number (50),
mode_line_proptrans_alist);
if (! NILP (tem))
XSETCDR (tem, Qnil);
}
}
}
offset = 0;
if (literal)
{
prec = precision - n;
switch (mode_line_target)
{
case MODE_LINE_NOPROP:
case MODE_LINE_TITLE:
n += store_mode_line_noprop (SDATA (elt), -1, prec);
break;
case MODE_LINE_STRING:
n += store_mode_line_string (NULL, elt, 1, 0, prec, Qnil);
break;
case MODE_LINE_DISPLAY:
n += display_string (NULL, elt, Qnil, 0, 0, it,
0, prec, 0, STRING_MULTIBYTE (elt));
break;
}
break;
}
while ((precision <= 0 || n < precision)
&& SREF (elt, offset) != 0
&& (mode_line_target != MODE_LINE_DISPLAY
|| it->current_x < it->last_visible_x))
{
int last_offset = offset;
while ((c = SREF (elt, offset++)) != '\0' && c != '%')
;
if (offset - 1 != last_offset)
{
int nchars, nbytes;
offset--;
prec = c_string_width (SDATA (elt) + last_offset,
offset - last_offset, precision - n,
&nchars, &nbytes);
switch (mode_line_target)
{
case MODE_LINE_NOPROP:
case MODE_LINE_TITLE:
n += store_mode_line_noprop (SDATA (elt) + last_offset, 0, prec);
break;
case MODE_LINE_STRING:
{
int bytepos = last_offset;
int charpos = string_byte_to_char (elt, bytepos);
int endpos = (precision <= 0
? string_byte_to_char (elt, offset)
: charpos + nchars);
n += store_mode_line_string (NULL,
Fsubstring (elt, make_number (charpos),
make_number (endpos)),
0, 0, 0, Qnil);
}
break;
case MODE_LINE_DISPLAY:
{
int bytepos = last_offset;
int charpos = string_byte_to_char (elt, bytepos);
if (precision <= 0)
nchars = string_byte_to_char (elt, offset) - charpos;
n += display_string (NULL, elt, Qnil, 0, charpos,
it, 0, nchars, 0,
STRING_MULTIBYTE (elt));
}
break;
}
}
else
{
int percent_position = offset;
field = 0;
while ((c = SREF (elt, offset++)) >= '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, props,
risky);
else if (c != 0)
{
int multibyte;
int bytepos, charpos;
unsigned char *spec;
bytepos = percent_position;
charpos = (STRING_MULTIBYTE (elt)
? string_byte_to_char (elt, bytepos)
: bytepos);
spec
= decode_mode_spec (it->w, c, field, prec, &multibyte);
switch (mode_line_target)
{
case MODE_LINE_NOPROP:
case MODE_LINE_TITLE:
n += store_mode_line_noprop (spec, field, prec);
break;
case MODE_LINE_STRING:
{
int len = strlen (spec);
Lisp_Object tem = make_string (spec, len);
props = Ftext_properties_at (make_number (charpos), elt);
n += store_mode_line_string (NULL, tem, 0, field, prec, props);
}
break;
case MODE_LINE_DISPLAY:
{
int nglyphs_before, nwritten;
nglyphs_before = it->glyph_row->used[TEXT_AREA];
nwritten = display_string (spec, Qnil, elt,
charpos, 0, it,
field, prec, 0,
multibyte);
if (nwritten > 0)
{
struct glyph *glyph
= (it->glyph_row->glyphs[TEXT_AREA]
+ nglyphs_before);
int i;
for (i = 0; i < nwritten; ++i)
{
glyph[i].object = elt;
glyph[i].charpos = charpos;
}
n += nwritten;
}
}
break;
}
}
else
break;
}
}
}
break;
case Lisp_Symbol:
{
register Lisp_Object tem;
if (NILP (Fget (elt, Qrisky_local_variable)))
risky = 1;
tem = Fboundp (elt);
if (!NILP (tem))
{
tem = Fsymbol_value (elt);
if (STRINGP (tem))
literal = 1;
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))
{
if (risky)
break;
if (CONSP (XCDR (elt)))
{
Lisp_Object spec;
spec = safe_eval (XCAR (XCDR (elt)));
n += display_mode_element (it, depth, field_width - n,
precision - n, spec, props,
risky);
}
}
else if (EQ (car, QCpropertize))
{
if (risky)
break;
if (CONSP (XCDR (elt)))
n += display_mode_element (it, depth, field_width - n,
precision - n, XCAR (XCDR (elt)),
XCDR (XCDR (elt)), risky);
}
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,
(! CONSP (XCDR (elt))
? field_width - n
: 0),
precision - n, XCAR (elt),
props, risky);
elt = XCDR (elt);
}
}
}
break;
default:
invalid:
elt = build_string ("*invalid*");
goto tail_recurse;
}
if (field_width > 0 && n < field_width)
{
switch (mode_line_target)
{
case MODE_LINE_NOPROP:
case MODE_LINE_TITLE:
n += store_mode_line_noprop ("", field_width - n, 0);
break;
case MODE_LINE_STRING:
n += store_mode_line_string ("", Qnil, 0, field_width - n, 0, Qnil);
break;
case MODE_LINE_DISPLAY:
n += display_string ("", Qnil, Qnil, 0, 0, it, field_width - n,
0, 0, 0);
break;
}
}
return n;
}
static int
store_mode_line_string (string, lisp_string, copy_string, field_width, precision, props)
char *string;
Lisp_Object lisp_string;
int copy_string;
int field_width;
int precision;
Lisp_Object props;
{
int len;
int n = 0;
if (string != NULL)
{
len = strlen (string);
if (precision > 0 && len > precision)
len = precision;
lisp_string = make_string (string, len);
if (NILP (props))
props = mode_line_string_face_prop;
else if (!NILP (mode_line_string_face))
{
Lisp_Object face = Fplist_get (props, Qface);
props = Fcopy_sequence (props);
if (NILP (face))
face = mode_line_string_face;
else
face = Fcons (face, Fcons (mode_line_string_face, Qnil));
props = Fplist_put (props, Qface, face);
}
Fadd_text_properties (make_number (0), make_number (len),
props, lisp_string);
}
else
{
len = XFASTINT (Flength (lisp_string));
if (precision > 0 && len > precision)
{
len = precision;
lisp_string = Fsubstring (lisp_string, make_number (0), make_number (len));
precision = -1;
}
if (!NILP (mode_line_string_face))
{
Lisp_Object face;
if (NILP (props))
props = Ftext_properties_at (make_number (0), lisp_string);
face = Fplist_get (props, Qface);
if (NILP (face))
face = mode_line_string_face;
else
face = Fcons (face, Fcons (mode_line_string_face, Qnil));
props = Fcons (Qface, Fcons (face, Qnil));
if (copy_string)
lisp_string = Fcopy_sequence (lisp_string);
}
if (!NILP (props))
Fadd_text_properties (make_number (0), make_number (len),
props, lisp_string);
}
if (len > 0)
{
mode_line_string_list = Fcons (lisp_string, mode_line_string_list);
n += len;
}
if (field_width > len)
{
field_width -= len;
lisp_string = Fmake_string (make_number (field_width), make_number (' '));
if (!NILP (props))
Fadd_text_properties (make_number (0), make_number (field_width),
props, lisp_string);
mode_line_string_list = Fcons (lisp_string, mode_line_string_list);
n += field_width;
}
return n;
}
DEFUN ("format-mode-line", Fformat_mode_line, Sformat_mode_line,
1, 4, 0,
doc: )
(format, face, window, buffer)
Lisp_Object format, face, window, buffer;
{
struct it it;
int len;
struct window *w;
struct buffer *old_buffer = NULL;
int face_id = -1;
int no_props = INTEGERP (face);
int count = SPECPDL_INDEX ();
Lisp_Object str;
int string_start = 0;
if (NILP (window))
window = selected_window;
CHECK_WINDOW (window);
w = XWINDOW (window);
if (NILP (buffer))
buffer = w->buffer;
CHECK_BUFFER (buffer);
if (NILP (format))
return build_string ("");
if (no_props)
face = Qnil;
if (!NILP (face))
{
if (EQ (face, Qt))
face = (EQ (window, selected_window) ? Qmode_line : Qmode_line_inactive);
face_id = lookup_named_face (XFRAME (WINDOW_FRAME (w)), face, 0, 0);
}
if (face_id < 0)
face_id = DEFAULT_FACE_ID;
if (XBUFFER (buffer) != current_buffer)
old_buffer = current_buffer;
record_unwind_protect (unwind_format_mode_line,
format_mode_line_unwind_data (old_buffer, 1));
mode_line_proptrans_alist = Qnil;
if (old_buffer)
set_buffer_internal_1 (XBUFFER (buffer));
init_iterator (&it, w, -1, -1, NULL, face_id);
if (no_props)
{
mode_line_target = MODE_LINE_NOPROP;
mode_line_string_face_prop = Qnil;
mode_line_string_list = Qnil;
string_start = MODE_LINE_NOPROP_LEN (0);
}
else
{
mode_line_target = MODE_LINE_STRING;
mode_line_string_list = Qnil;
mode_line_string_face = face;
mode_line_string_face_prop
= (NILP (face) ? Qnil : Fcons (Qface, Fcons (face, Qnil)));
}
push_frame_kboard (it.f);
display_mode_element (&it, 0, 0, 0, format, Qnil, 0);
pop_frame_kboard ();
if (no_props)
{
len = MODE_LINE_NOPROP_LEN (string_start);
str = make_string (mode_line_noprop_buf + string_start, len);
}
else
{
mode_line_string_list = Fnreverse (mode_line_string_list);
str = Fmapconcat (intern ("identity"), mode_line_string_list,
make_string ("", 0));
}
unbind_to (count, Qnil);
return str;
}
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 const char power_letter[] =
{
0,
'k',
'M',
'G',
'T',
'P',
'E',
'Z',
'Y'
};
static void
pint2hrstr (buf, width, d)
char *buf;
int width;
int d;
{
int quotient = d;
int remainder = 0;
int tenths = -1;
int exponent = 0;
int length;
char * psuffix;
char * p;
if (1000 <= quotient)
{
do
{
remainder = quotient % 1000;
quotient /= 1000;
exponent++;
}
while (1000 <= quotient);
if (quotient <= 9)
{
tenths = remainder / 100;
if (50 <= remainder % 100)
{
if (tenths < 9)
tenths++;
else
{
quotient++;
if (quotient == 10)
tenths = -1;
else
tenths = 0;
}
}
}
else
if (500 <= remainder)
{
if (quotient < 999)
quotient++;
else
{
quotient = 1;
exponent++;
tenths = 0;
}
}
}
if (tenths == -1 && quotient <= 99)
if (quotient <= 9)
length = 1;
else
length = 2;
else
length = 3;
p = psuffix = buf + max (width, length);
if (exponent)
*psuffix++ = power_letter[exponent];
*psuffix = '\0';
if (tenths >= 0)
{
*--p = '0' + tenths;
*--p = '.';
}
do
{
int digit = quotient % 10;
*--p = '0' + digit;
}
while ((quotient /= 10) != 0);
while (buf < p)
*--p = ' ';
}
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);
const 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 = SDATA (eoltype);
eol_str_len = SBYTES (eoltype);
}
else if (INTEGERP (eoltype)
&& CHAR_VALID_P (XINT (eoltype), 0))
{
unsigned char *tmp = (unsigned char *) alloca (MAX_MULTIBYTE_LENGTH);
eol_str_len = CHAR_STRING (XINT (eoltype), tmp);
eol_str = tmp;
}
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 = current_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 (mode_line_target == MODE_LINE_NOPROP ||
mode_line_target == MODE_LINE_STRING)
return "--";
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':
if (mode_line_target == MODE_LINE_TITLE)
return "";
else
{
int col = (int) current_column ();
w->column_number_displayed = make_number (col);
pint2str (decode_mode_spec_buf, field_width, col);
return decode_mode_spec_buf;
}
case 'e':
#ifndef SYSTEM_MALLOC
{
if (NILP (Vmemory_full))
return "";
else
return "!MEM FULL! ";
}
#else
return "";
#endif
case 'F':
if (!NILP (f->title))
return (char *) SDATA (f->title);
if (f->explicit_name || ! FRAME_WINDOW_P (f))
return (char *) SDATA (f->name);
return "Emacs";
case 'f':
obj = b->filename;
break;
case 'i':
{
int size = ZV - BEGV;
pint2str (decode_mode_spec_buf, field_width, size);
return decode_mode_spec_buf;
}
case 'I':
{
int size = ZV - BEGV;
pint2hrstr (decode_mode_spec_buf, field_width, size);
return decode_mode_spec_buf;
}
case 'l':
{
int startpos, startpos_byte, line, linepos, linepos_byte;
int topline, nlines, junk, height;
if (mode_line_target == MODE_LINE_TITLE)
return "";
startpos = XMARKER (w->start)->charpos;
startpos_byte = marker_byte_position (w->start);
height = WINDOW_TOTAL_LINES (w);
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 (Fcurrent_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 *) SDATA (obj);
}
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;
row->extra_line_spacing = it->max_extra_line_spacing;
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);
row->extra_line_spacing = max (row->extra_line_spacing,
it->max_extra_line_spacing);
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 NILP (XCDR (tem)) ? 1 : 2;
}
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 NILP (XCDR (tem)) ? 1 : 2;
}
}
}
return 0;
}
#define NUMVAL(X) \
((INTEGERP (X) || FLOATP (X)) \
? XFLOATINT (X) \
: - 1)
int
calc_pixel_width_or_height (res, it, prop, font, width_p, align_to)
double *res;
struct it *it;
Lisp_Object prop;
void *font;
int width_p, *align_to;
{
double pixels;
#define OK_PIXELS(val) ((*res = (double)(val)), 1)
#define OK_ALIGN_TO(val) ((*align_to = (int)(val)), 1)
if (NILP (prop))
return OK_PIXELS (0);
if (SYMBOLP (prop))
{
if (SCHARS (SYMBOL_NAME (prop)) == 2)
{
char *unit = SDATA (SYMBOL_NAME (prop));
if (unit[0] == 'i' && unit[1] == 'n')
pixels = 1.0;
else if (unit[0] == 'm' && unit[1] == 'm')
pixels = 25.4;
else if (unit[0] == 'c' && unit[1] == 'm')
pixels = 2.54;
else
pixels = 0;
if (pixels > 0)
{
double ppi;
#ifdef HAVE_WINDOW_SYSTEM
if (FRAME_WINDOW_P (it->f)
&& (ppi = (width_p
? FRAME_X_DISPLAY_INFO (it->f)->resx
: FRAME_X_DISPLAY_INFO (it->f)->resy),
ppi > 0))
return OK_PIXELS (ppi / pixels);
#endif
if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0)
|| (CONSP (Vdisplay_pixels_per_inch)
&& (ppi = (width_p
? NUMVAL (XCAR (Vdisplay_pixels_per_inch))
: NUMVAL (XCDR (Vdisplay_pixels_per_inch))),
ppi > 0)))
return OK_PIXELS (ppi / pixels);
return 0;
}
}
#ifdef HAVE_WINDOW_SYSTEM
if (EQ (prop, Qheight))
return OK_PIXELS (font ? FONT_HEIGHT ((XFontStruct *)font) : FRAME_LINE_HEIGHT (it->f));
if (EQ (prop, Qwidth))
return OK_PIXELS (font ? FONT_WIDTH ((XFontStruct *)font) : FRAME_COLUMN_WIDTH (it->f));
#else
if (EQ (prop, Qheight) || EQ (prop, Qwidth))
return OK_PIXELS (1);
#endif
if (EQ (prop, Qtext))
return OK_PIXELS (width_p
? window_box_width (it->w, TEXT_AREA)
: WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w));
if (align_to && *align_to < 0)
{
*res = 0;
if (EQ (prop, Qleft))
return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA));
if (EQ (prop, Qright))
return OK_ALIGN_TO (window_box_right_offset (it->w, TEXT_AREA));
if (EQ (prop, Qcenter))
return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA)
+ window_box_width (it->w, TEXT_AREA) / 2);
if (EQ (prop, Qleft_fringe))
return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
? WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (it->w)
: window_box_right_offset (it->w, LEFT_MARGIN_AREA));
if (EQ (prop, Qright_fringe))
return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
? window_box_right_offset (it->w, RIGHT_MARGIN_AREA)
: window_box_right_offset (it->w, TEXT_AREA));
if (EQ (prop, Qleft_margin))
return OK_ALIGN_TO (window_box_left_offset (it->w, LEFT_MARGIN_AREA));
if (EQ (prop, Qright_margin))
return OK_ALIGN_TO (window_box_left_offset (it->w, RIGHT_MARGIN_AREA));
if (EQ (prop, Qscroll_bar))
return OK_ALIGN_TO (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w)
? 0
: (window_box_right_offset (it->w, RIGHT_MARGIN_AREA)
+ (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
? WINDOW_RIGHT_FRINGE_WIDTH (it->w)
: 0)));
}
else
{
if (EQ (prop, Qleft_fringe))
return OK_PIXELS (WINDOW_LEFT_FRINGE_WIDTH (it->w));
if (EQ (prop, Qright_fringe))
return OK_PIXELS (WINDOW_RIGHT_FRINGE_WIDTH (it->w));
if (EQ (prop, Qleft_margin))
return OK_PIXELS (WINDOW_LEFT_MARGIN_WIDTH (it->w));
if (EQ (prop, Qright_margin))
return OK_PIXELS (WINDOW_RIGHT_MARGIN_WIDTH (it->w));
if (EQ (prop, Qscroll_bar))
return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w));
}
prop = Fbuffer_local_value (prop, it->w->buffer);
}
if (INTEGERP (prop) || FLOATP (prop))
{
int base_unit = (width_p
? FRAME_COLUMN_WIDTH (it->f)
: FRAME_LINE_HEIGHT (it->f));
return OK_PIXELS (XFLOATINT (prop) * base_unit);
}
if (CONSP (prop))
{
Lisp_Object car = XCAR (prop);
Lisp_Object cdr = XCDR (prop);
if (SYMBOLP (car))
{
#ifdef HAVE_WINDOW_SYSTEM
if (valid_image_p (prop))
{
int id = lookup_image (it->f, prop);
struct image *img = IMAGE_FROM_ID (it->f, id);
return OK_PIXELS (width_p ? img->width : img->height);
}
#endif
if (EQ (car, Qplus) || EQ (car, Qminus))
{
int first = 1;
double px;
pixels = 0;
while (CONSP (cdr))
{
if (!calc_pixel_width_or_height (&px, it, XCAR (cdr),
font, width_p, align_to))
return 0;
if (first)
pixels = (EQ (car, Qplus) ? px : -px), first = 0;
else
pixels += px;
cdr = XCDR (cdr);
}
if (EQ (car, Qminus))
pixels = -pixels;
return OK_PIXELS (pixels);
}
car = Fbuffer_local_value (car, it->w->buffer);
}
if (INTEGERP (car) || FLOATP (car))
{
double fact;
pixels = XFLOATINT (car);
if (NILP (cdr))
return OK_PIXELS (pixels);
if (calc_pixel_width_or_height (&fact, it, cdr,
font, width_p, align_to))
return OK_PIXELS (pixels * fact);
return 0;
}
return 0;
}
return 0;
}
#ifdef HAVE_WINDOW_SYSTEM
#if GLYPH_DEBUG
void
dump_glyph_string (s)
struct glyph_string *s;
{
fprintf (stderr, "glyph string\n");
fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
s->x, s->y, s->width, s->height);
fprintf (stderr, " ybase = %d\n", s->ybase);
fprintf (stderr, " hl = %d\n", s->hl);
fprintf (stderr, " left overhang = %d, right = %d\n",
s->left_overhang, s->right_overhang);
fprintf (stderr, " nchars = %d\n", s->nchars);
fprintf (stderr, " extends to end of line = %d\n",
s->extends_to_end_of_line_p);
fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
fprintf (stderr, " bg width = %d\n", s->background_width);
}
#endif
#ifdef HAVE_NTGUI
#define OPTIONAL_HDC(hdc) hdc,
#define DECLARE_HDC(hdc) HDC hdc;
#define ALLOCATE_HDC(hdc, f) hdc = get_frame_dc ((f))
#define RELEASE_HDC(hdc, f) release_frame_dc ((f), (hdc))
#endif
#ifndef OPTIONAL_HDC
#define OPTIONAL_HDC(hdc)
#define DECLARE_HDC(hdc)
#define ALLOCATE_HDC(hdc, f)
#define RELEASE_HDC(hdc, f)
#endif
static void
init_glyph_string (s, OPTIONAL_HDC (hdc) char2b, w, row, area, start, hl)
struct glyph_string *s;
DECLARE_HDC (hdc)
XChar2b *char2b;
struct window *w;
struct glyph_row *row;
enum glyph_row_area area;
int start;
enum draw_glyphs_face hl;
{
bzero (s, sizeof *s);
s->w = w;
s->f = XFRAME (w->frame);
#ifdef HAVE_NTGUI
s->hdc = hdc;
#endif
s->display = FRAME_X_DISPLAY (s->f);
s->window = FRAME_X_WINDOW (s->f);
s->char2b = char2b;
s->hl = hl;
s->row = row;
s->area = area;
s->first_glyph = row->glyphs[area] + start;
s->height = row->height;
s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
if (WINDOWP (s->f->tool_bar_window)
&& s->w == XWINDOW (s->f->tool_bar_window))
s->y -= FRAME_INTERNAL_BORDER_WIDTH (s->f);
s->ybase = s->y + row->ascent;
}
static INLINE void
append_glyph_string_lists (head, tail, h, t)
struct glyph_string **head, **tail;
struct glyph_string *h, *t;
{
if (h)
{
if (*head)
(*tail)->next = h;
else
*head = h;
h->prev = *tail;
*tail = t;
}
}
static INLINE void
prepend_glyph_string_lists (head, tail, h, t)
struct glyph_string **head, **tail;
struct glyph_string *h, *t;
{
if (h)
{
if (*head)
(*head)->prev = t;
else
*tail = t;
t->next = *head;
*head = h;
}
}
static INLINE void
append_glyph_string (head, tail, s)
struct glyph_string **head, **tail;
struct glyph_string *s;
{
s->next = s->prev = NULL;
append_glyph_string_lists (head, tail, s, s);
}
static INLINE struct face *
get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
struct frame *f;
struct glyph *glyph;
XChar2b *char2b;
int *two_byte_p;
{
struct face *face;
xassert (glyph->type == CHAR_GLYPH);
face = FACE_FROM_ID (f, glyph->face_id);
if (two_byte_p)
*two_byte_p = 0;
if (!glyph->multibyte_p)
{
STORE_XCHAR2B (char2b, 0, glyph->u.ch);
}
else if (glyph->u.ch < 128)
{
STORE_XCHAR2B (char2b, 0, glyph->u.ch);
}
else
{
int c1, c2, charset;
SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
if (c2 > 0)
STORE_XCHAR2B (char2b, c1, c2);
else
STORE_XCHAR2B (char2b, 0, c1);
if (charset != CHARSET_ASCII)
{
struct font_info *font_info
= FONT_INFO_FROM_ID (f, face->font_info_id);
if (font_info)
glyph->font_type
= rif->encode_char (glyph->u.ch, char2b, font_info, two_byte_p);
}
}
xassert (face != NULL);
PREPARE_FACE_FOR_DISPLAY (f, face);
return face;
}
static int
fill_composite_glyph_string (s, faces, overlaps)
struct glyph_string *s;
struct face **faces;
int overlaps;
{
int i;
xassert (s);
s->for_overlaps = overlaps;
s->face = faces[s->gidx];
s->font = s->face->font;
s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
++s->nchars;
for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
++s->nchars;
s->width = s->first_glyph->pixel_width;
if (s->font == NULL)
{
s->font_not_found_p = 1;
s->font = FRAME_FONT (s->f);
}
s->ybase += s->first_glyph->voffset;
xassert (s->face && s->face->gc);
s->two_byte_p = 1;
return s->gidx + s->nchars;
}
static int
fill_glyph_string (s, face_id, start, end, overlaps)
struct glyph_string *s;
int face_id;
int start, end, overlaps;
{
struct glyph *glyph, *last;
int voffset;
int glyph_not_available_p;
xassert (s->f == XFRAME (s->w->frame));
xassert (s->nchars == 0);
xassert (start >= 0 && end > start);
s->for_overlaps = overlaps,
glyph = s->row->glyphs[s->area] + start;
last = s->row->glyphs[s->area] + end;
voffset = glyph->voffset;
glyph_not_available_p = glyph->glyph_not_available_p;
while (glyph < last
&& glyph->type == CHAR_GLYPH
&& glyph->voffset == voffset
&& glyph->face_id == face_id
&& glyph->glyph_not_available_p == glyph_not_available_p)
{
int two_byte_p;
s->face = get_glyph_face_and_encoding (s->f, glyph,
s->char2b + s->nchars,
&two_byte_p);
s->two_byte_p = two_byte_p;
++s->nchars;
xassert (s->nchars <= end - start);
s->width += glyph->pixel_width;
++glyph;
}
s->font = s->face->font;
s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
if (s->font == NULL || glyph_not_available_p)
{
s->font_not_found_p = 1;
s->font = FRAME_FONT (s->f);
}
s->ybase += voffset;
xassert (s->face && s->face->gc);
return glyph - s->row->glyphs[s->area];
}
static void
fill_image_glyph_string (s)
struct glyph_string *s;
{
xassert (s->first_glyph->type == IMAGE_GLYPH);
s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
xassert (s->img);
s->slice = s->first_glyph->slice;
s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
s->font = s->face->font;
s->width = s->first_glyph->pixel_width;
s->ybase += s->first_glyph->voffset;
}
static int
fill_stretch_glyph_string (s, row, area, start, end)
struct glyph_string *s;
struct glyph_row *row;
enum glyph_row_area area;
int start, end;
{
struct glyph *glyph, *last;
int voffset, face_id;
xassert (s->first_glyph->type == STRETCH_GLYPH);
glyph = s->row->glyphs[s->area] + start;
last = s->row->glyphs[s->area] + end;
face_id = glyph->face_id;
s->face = FACE_FROM_ID (s->f, face_id);
s->font = s->face->font;
s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
s->width = glyph->pixel_width;
s->nchars = 1;
voffset = glyph->voffset;
for (++glyph;
(glyph < last
&& glyph->type == STRETCH_GLYPH
&& glyph->voffset == voffset
&& glyph->face_id == face_id);
++glyph)
s->width += glyph->pixel_width;
s->ybase += voffset;
xassert (s->face);
return glyph - s->row->glyphs[s->area];
}
void
x_get_glyph_overhangs (glyph, f, left, right)
struct glyph *glyph;
struct frame *f;
int *left, *right;
{
*left = *right = 0;
if (glyph->type == CHAR_GLYPH)
{
XFontStruct *font;
struct face *face;
struct font_info *font_info;
XChar2b char2b;
XCharStruct *pcm;
face = get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
font = face->font;
font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
if (font
&& (pcm = rif->per_char_metric (font, &char2b, glyph->font_type)))
{
if (pcm->rbearing > pcm->width)
*right = pcm->rbearing - pcm->width;
if (pcm->lbearing < 0)
*left = -pcm->lbearing;
}
}
}
static int
left_overwritten (s)
struct glyph_string *s;
{
int k;
if (s->left_overhang)
{
int x = 0, i;
struct glyph *glyphs = s->row->glyphs[s->area];
int first = s->first_glyph - glyphs;
for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
x -= glyphs[i].pixel_width;
k = i + 1;
}
else
k = -1;
return k;
}
static int
left_overwriting (s)
struct glyph_string *s;
{
int i, k, x;
struct glyph *glyphs = s->row->glyphs[s->area];
int first = s->first_glyph - glyphs;
k = -1;
x = 0;
for (i = first - 1; i >= 0; --i)
{
int left, right;
x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
if (x + right > 0)
k = i;
x -= glyphs[i].pixel_width;
}
return k;
}
static int
right_overwritten (s)
struct glyph_string *s;
{
int k = -1;
if (s->right_overhang)
{
int x = 0, i;
struct glyph *glyphs = s->row->glyphs[s->area];
int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
int end = s->row->used[s->area];
for (i = first; i < end && s->right_overhang > x; ++i)
x += glyphs[i].pixel_width;
k = i;
}
return k;
}
static int
right_overwriting (s)
struct glyph_string *s;
{
int i, k, x;
int end = s->row->used[s->area];
struct glyph *glyphs = s->row->glyphs[s->area];
int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
k = -1;
x = 0;
for (i = first; i < end; ++i)
{
int left, right;
x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
if (x - left < 0)
k = i;
x += glyphs[i].pixel_width;
}
return k;
}
static INLINE struct face *
get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p)
struct frame *f;
int c, face_id;
XChar2b *char2b;
int multibyte_p, display_p;
{
struct face *face = FACE_FROM_ID (f, face_id);
if (!multibyte_p)
{
STORE_XCHAR2B (char2b, 0, c);
face_id = FACE_FOR_CHAR (f, face, c);
face = FACE_FROM_ID (f, face_id);
}
else if (c < 128)
{
STORE_XCHAR2B (char2b, 0, c);
}
else
{
int c1, c2, charset;
SPLIT_CHAR (c, charset, c1, c2);
if (c2 > 0)
STORE_XCHAR2B (char2b, c1, c2);
else
STORE_XCHAR2B (char2b, 0, c1);
if (face->font != NULL)
{
struct font_info *font_info
= FONT_INFO_FROM_ID (f, face->font_info_id);
if (font_info)
rif->encode_char (c, char2b, font_info, 0);
}
}
#ifdef HAVE_X_WINDOWS
if (display_p)
#endif
{
xassert (face != NULL);
PREPARE_FACE_FOR_DISPLAY (f, face);
}
return face;
}
static INLINE void
set_glyph_string_background_width (s, start, last_x)
struct glyph_string *s;
int start;
int last_x;
{
if (start == s->row->used[s->area]
&& s->area == TEXT_AREA
&& ((s->row->fill_line_p
&& (s->hl == DRAW_NORMAL_TEXT
|| s->hl == DRAW_IMAGE_RAISED
|| s->hl == DRAW_IMAGE_SUNKEN))
|| s->hl == DRAW_MOUSE_FACE))
s->extends_to_end_of_line_p = 1;
if (s->extends_to_end_of_line_p)
s->background_width = last_x - s->x + 1;
else
s->background_width = s->width;
}
static void
compute_overhangs_and_x (s, x, backward_p)
struct glyph_string *s;
int x;
int backward_p;
{
if (backward_p)
{
while (s)
{
if (rif->compute_glyph_string_overhangs)
rif->compute_glyph_string_overhangs (s);
x -= s->width;
s->x = x;
s = s->prev;
}
}
else
{
while (s)
{
if (rif->compute_glyph_string_overhangs)
rif->compute_glyph_string_overhangs (s);
s->x = x;
x += s->width;
s = s->next;
}
}
}
#ifdef HAVE_NTGUI
#define INIT_GLYPH_STRING(s, char2b, w, row, area, start, hl) \
init_glyph_string (s, hdc, char2b, w, row, area, start, hl)
#else
#define INIT_GLYPH_STRING(s, char2b, w, row, area, start, hl) \
init_glyph_string (s, char2b, w, row, area, start, hl)
#endif
#define BUILD_STRETCH_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
do \
{ \
s = (struct glyph_string *) alloca (sizeof *s); \
INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL); \
START = fill_stretch_glyph_string (s, row, area, START, END); \
append_glyph_string (&HEAD, &TAIL, s); \
s->x = (X); \
} \
while (0)
#define BUILD_IMAGE_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
do \
{ \
s = (struct glyph_string *) alloca (sizeof *s); \
INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL); \
fill_image_glyph_string (s); \
append_glyph_string (&HEAD, &TAIL, s); \
++START; \
s->x = (X); \
} \
while (0)
#define BUILD_CHAR_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
do \
{ \
int c, face_id; \
XChar2b *char2b; \
\
c = (row)->glyphs[area][START].u.ch; \
face_id = (row)->glyphs[area][START].face_id; \
\
s = (struct glyph_string *) alloca (sizeof *s); \
char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL); \
append_glyph_string (&HEAD, &TAIL, s); \
s->x = (X); \
START = fill_glyph_string (s, face_id, START, END, overlaps); \
} \
while (0)
#define BUILD_COMPOSITE_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
do { \
int cmp_id = (row)->glyphs[area][START].u.cmp_id; \
int face_id = (row)->glyphs[area][START].face_id; \
struct face *base_face = FACE_FROM_ID (f, face_id); \
struct composition *cmp = composition_table[cmp_id]; \
int glyph_len = cmp->glyph_len; \
XChar2b *char2b; \
struct face **faces; \
struct glyph_string *first_s = NULL; \
int n; \
\
base_face = base_face->ascii_face; \
char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
\
for (n = 0; n < glyph_len; n++) \
{ \
int c = COMPOSITION_GLYPH (cmp, n); \
int this_face_id = FACE_FOR_CHAR (f, base_face, c); \
faces[n] = FACE_FROM_ID (f, this_face_id); \
get_char_face_and_encoding (f, c, this_face_id, \
char2b + n, 1, 1); \
} \
\
\
for (n = 0; n < cmp->glyph_len;) \
{ \
s = (struct glyph_string *) alloca (sizeof *s); \
INIT_GLYPH_STRING (s, char2b + n, w, row, area, START, HL); \
append_glyph_string (&(HEAD), &(TAIL), s); \
s->cmp = cmp; \
s->gidx = n; \
s->x = (X); \
\
if (n == 0) \
first_s = s; \
\
n = fill_composite_glyph_string (s, faces, overlaps); \
} \
\
++START; \
s = first_s; \
} while (0)
#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
do \
{ \
HEAD = TAIL = NULL; \
while (START < END) \
{ \
struct glyph *first_glyph = (row)->glyphs[area] + START; \
switch (first_glyph->type) \
{ \
case CHAR_GLYPH: \
BUILD_CHAR_GLYPH_STRINGS (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
\
case COMPOSITE_GLYPH: \
BUILD_COMPOSITE_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
\
case STRETCH_GLYPH: \
BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
\
case IMAGE_GLYPH: \
BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
\
default: \
abort (); \
} \
\
set_glyph_string_background_width (s, START, LAST_X); \
(X) += s->width; \
} \
} \
while (0)
static int
draw_glyphs (w, x, row, area, start, end, hl, overlaps)
struct window *w;
int x;
struct glyph_row *row;
enum glyph_row_area area;
int start, end;
enum draw_glyphs_face hl;
int overlaps;
{
struct glyph_string *head, *tail;
struct glyph_string *s;
struct glyph_string *clip_head = NULL, *clip_tail = NULL;
int last_x, area_width;
int x_reached;
int i, j;
struct frame *f = XFRAME (WINDOW_FRAME (w));
DECLARE_HDC (hdc);
ALLOCATE_HDC (hdc, f);
end = min (end, row->used[area]);
start = max (0, start);
start = min (end, start);
if (row->full_width_p)
{
x += WINDOW_LEFT_EDGE_X (w);
last_x = WINDOW_LEFT_EDGE_X (w) + WINDOW_TOTAL_WIDTH (w);
}
else
{
int area_left = window_box_left (w, area);
x += area_left;
area_width = window_box_width (w, area);
last_x = area_left + area_width;
}
i = start;
BUILD_GLYPH_STRINGS (i, end, head, tail, hl, x, last_x);
if (tail)
x_reached = tail->x + tail->background_width;
else
x_reached = x;
if (head && !overlaps && row->contains_overlapping_glyphs_p)
{
int dummy_x = 0;
struct glyph_string *h, *t;
if (rif->compute_glyph_string_overhangs)
for (s = head; s; s = s->next)
rif->compute_glyph_string_overhangs (s);
i = left_overwritten (head);
if (i >= 0)
{
j = i;
BUILD_GLYPH_STRINGS (j, start, h, t,
DRAW_NORMAL_TEXT, dummy_x, last_x);
start = i;
compute_overhangs_and_x (t, head->x, 1);
prepend_glyph_string_lists (&head, &tail, h, t);
clip_head = head;
}
i = left_overwriting (head);
if (i >= 0)
{
clip_head = head;
BUILD_GLYPH_STRINGS (i, start, h, t,
DRAW_NORMAL_TEXT, dummy_x, last_x);
for (s = h; s; s = s->next)
s->background_filled_p = 1;
compute_overhangs_and_x (t, head->x, 1);
prepend_glyph_string_lists (&head, &tail, h, t);
}
i = right_overwritten (tail);
if (i >= 0)
{
BUILD_GLYPH_STRINGS (end, i, h, t,
DRAW_NORMAL_TEXT, x, last_x);
compute_overhangs_and_x (h, tail->x + tail->width, 0);
append_glyph_string_lists (&head, &tail, h, t);
clip_tail = tail;
}
i = right_overwriting (tail);
if (i >= 0)
{
clip_tail = tail;
BUILD_GLYPH_STRINGS (end, i, h, t,
DRAW_NORMAL_TEXT, x, last_x);
for (s = h; s; s = s->next)
s->background_filled_p = 1;
compute_overhangs_and_x (h, tail->x + tail->width, 0);
append_glyph_string_lists (&head, &tail, h, t);
}
if (clip_head || clip_tail)
for (s = head; s; s = s->next)
{
s->clip_head = clip_head;
s->clip_tail = clip_tail;
}
}
for (s = head; s; s = s->next)
rif->draw_glyph_string (s);
if (area == TEXT_AREA
&& !row->full_width_p
&& !overlaps)
{
int x0 = clip_head ? clip_head->x : (head ? head->x : x);
int x1 = (clip_tail ? clip_tail->x + clip_tail->background_width
: (tail ? tail->x + tail->background_width : x));
int text_left = window_box_left (w, TEXT_AREA);
x0 -= text_left;
x1 -= text_left;
notice_overwritten_cursor (w, TEXT_AREA, x0, x1,
row->y, MATRIX_ROW_BOTTOM_Y (row));
}
if (row->full_width_p)
x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
else
x_reached -= window_box_left (w, area);
RELEASE_HDC (hdc, f);
return x_reached;
}
#define IT_EXPAND_MATRIX_WIDTH(it, area) \
{ \
if (!fonts_changed_p \
&& (it->glyph_row->glyphs[area] \
< it->glyph_row->glyphs[area + 1])) \
{ \
it->w->ncols_scale_factor++; \
fonts_changed_p = 1; \
} \
}
static INLINE void
append_glyph (it)
struct it *it;
{
struct glyph *glyph;
enum glyph_row_area area = it->area;
xassert (it->glyph_row);
xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
if (glyph < it->glyph_row->glyphs[area + 1])
{
glyph->charpos = CHARPOS (it->position);
glyph->object = it->object;
glyph->pixel_width = it->pixel_width;
glyph->ascent = it->ascent;
glyph->descent = it->descent;
glyph->voffset = it->voffset;
glyph->type = CHAR_GLYPH;
glyph->multibyte_p = it->multibyte_p;
glyph->left_box_line_p = it->start_of_box_run_p;
glyph->right_box_line_p = it->end_of_box_run_p;
glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
|| it->phys_descent > it->descent);
glyph->padding_p = 0;
glyph->glyph_not_available_p = it->glyph_not_available_p;
glyph->face_id = it->face_id;
glyph->u.ch = it->char_to_display;
glyph->slice = null_glyph_slice;
glyph->font_type = FONT_TYPE_UNKNOWN;
++it->glyph_row->used[area];
}
else
IT_EXPAND_MATRIX_WIDTH (it, area);
}
static INLINE void
append_composite_glyph (it)
struct it *it;
{
struct glyph *glyph;
enum glyph_row_area area = it->area;
xassert (it->glyph_row);
glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
if (glyph < it->glyph_row->glyphs[area + 1])
{
glyph->charpos = CHARPOS (it->position);
glyph->object = it->object;
glyph->pixel_width = it->pixel_width;
glyph->ascent = it->ascent;
glyph->descent = it->descent;
glyph->voffset = it->voffset;
glyph->type = COMPOSITE_GLYPH;
glyph->multibyte_p = it->multibyte_p;
glyph->left_box_line_p = it->start_of_box_run_p;
glyph->right_box_line_p = it->end_of_box_run_p;
glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
|| it->phys_descent > it->descent);
glyph->padding_p = 0;
glyph->glyph_not_available_p = 0;
glyph->face_id = it->face_id;
glyph->u.cmp_id = it->cmp_id;
glyph->slice = null_glyph_slice;
glyph->font_type = FONT_TYPE_UNKNOWN;
++it->glyph_row->used[area];
}
else
IT_EXPAND_MATRIX_WIDTH (it, area);
}
static INLINE void
take_vertical_position_into_account (it)
struct it *it;
{
if (it->voffset)
{
if (it->voffset < 0)
it->ascent -= it->voffset;
else
it->descent += it->voffset;
}
}
static void
produce_image_glyph (it)
struct it *it;
{
struct image *img;
struct face *face;
int glyph_ascent, crop;
struct glyph_slice slice;
xassert (it->what == IT_IMAGE);
face = FACE_FROM_ID (it->f, it->face_id);
xassert (face);
PREPARE_FACE_FOR_DISPLAY (it->f, face);
if (it->image_id < 0)
{
it->ascent = it->phys_ascent = 0;
it->descent = it->phys_descent = 0;
it->pixel_width = 0;
it->nglyphs = 0;
return;
}
img = IMAGE_FROM_ID (it->f, it->image_id);
xassert (img);
prepare_image_for_display (it->f, img);
slice.x = slice.y = 0;
slice.width = img->width;
slice.height = img->height;
if (INTEGERP (it->slice.x))
slice.x = XINT (it->slice.x);
else if (FLOATP (it->slice.x))
slice.x = XFLOAT_DATA (it->slice.x) * img->width;
if (INTEGERP (it->slice.y))
slice.y = XINT (it->slice.y);
else if (FLOATP (it->slice.y))
slice.y = XFLOAT_DATA (it->slice.y) * img->height;
if (INTEGERP (it->slice.width))
slice.width = XINT (it->slice.width);
else if (FLOATP (it->slice.width))
slice.width = XFLOAT_DATA (it->slice.width) * img->width;
if (INTEGERP (it->slice.height))
slice.height = XINT (it->slice.height);
else if (FLOATP (it->slice.height))
slice.height = XFLOAT_DATA (it->slice.height) * img->height;
if (slice.x >= img->width)
slice.x = img->width;
if (slice.y >= img->height)
slice.y = img->height;
if (slice.x + slice.width >= img->width)
slice.width = img->width - slice.x;
if (slice.y + slice.height > img->height)
slice.height = img->height - slice.y;
if (slice.width == 0 || slice.height == 0)
return;
it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face, &slice);
it->descent = slice.height - glyph_ascent;
if (slice.y == 0)
it->descent += img->vmargin;
if (slice.y + slice.height == img->height)
it->descent += img->vmargin;
it->phys_descent = it->descent;
it->pixel_width = slice.width;
if (slice.x == 0)
it->pixel_width += img->hmargin;
if (slice.x + slice.width == img->width)
it->pixel_width += img->hmargin;
if (it->descent < 0)
it->descent = 0;
#if 0
int face_ascent = face->font ? FONT_BASE (face->font) : FRAME_BASELINE_OFFSET (it->f);
if (face_ascent > it->ascent)
it->ascent = it->phys_ascent = face_ascent;
#endif
it->nglyphs = 1;
if (face->box != FACE_NO_BOX)
{
if (face->box_line_width > 0)
{
if (slice.y == 0)
it->ascent += face->box_line_width;
if (slice.y + slice.height == img->height)
it->descent += face->box_line_width;
}
if (it->start_of_box_run_p && slice.x == 0)
it->pixel_width += abs (face->box_line_width);
if (it->end_of_box_run_p && slice.x + slice.width == img->width)
it->pixel_width += abs (face->box_line_width);
}
take_vertical_position_into_account (it);
if ((crop = it->pixel_width - (it->last_visible_x - it->current_x), crop > 0)
&& (it->hpos == 0 || it->pixel_width > it->last_visible_x / 4))
{
it->pixel_width -= crop;
slice.width -= crop;
}
if (it->glyph_row)
{
struct glyph *glyph;
enum glyph_row_area area = it->area;
glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
if (glyph < it->glyph_row->glyphs[area + 1])
{
glyph->charpos = CHARPOS (it->position);
glyph->object = it->object;
glyph->pixel_width = it->pixel_width;
glyph->ascent = glyph_ascent;
glyph->descent = it->descent;
glyph->voffset = it->voffset;
glyph->type = IMAGE_GLYPH;
glyph->multibyte_p = it->multibyte_p;
glyph->left_box_line_p = it->start_of_box_run_p;
glyph->right_box_line_p = it->end_of_box_run_p;
glyph->overlaps_vertically_p = 0;
glyph->padding_p = 0;
glyph->glyph_not_available_p = 0;
glyph->face_id = it->face_id;
glyph->u.img_id = img->id;
glyph->slice = slice;
glyph->font_type = FONT_TYPE_UNKNOWN;
++it->glyph_row->used[area];
}
else
IT_EXPAND_MATRIX_WIDTH (it, area);
}
}
static void
append_stretch_glyph (it, object, width, height, ascent)
struct it *it;
Lisp_Object object;
int width, height;
int ascent;
{
struct glyph *glyph;
enum glyph_row_area area = it->area;
xassert (ascent >= 0 && ascent <= height);
glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
if (glyph < it->glyph_row->glyphs[area + 1])
{
glyph->charpos = CHARPOS (it->position);
glyph->object = object;
glyph->pixel_width = width;
glyph->ascent = ascent;
glyph->descent = height - ascent;
glyph->voffset = it->voffset;
glyph->type = STRETCH_GLYPH;
glyph->multibyte_p = it->multibyte_p;
glyph->left_box_line_p = it->start_of_box_run_p;
glyph->right_box_line_p = it->end_of_box_run_p;
glyph->overlaps_vertically_p = 0;
glyph->padding_p = 0;
glyph->glyph_not_available_p = 0;
glyph->face_id = it->face_id;
glyph->u.stretch.ascent = ascent;
glyph->u.stretch.height = height;
glyph->slice = null_glyph_slice;
glyph->font_type = FONT_TYPE_UNKNOWN;
++it->glyph_row->used[area];
}
else
IT_EXPAND_MATRIX_WIDTH (it, area);
}
static void
produce_stretch_glyph (it)
struct it *it;
{
Lisp_Object prop, plist;
int width = 0, height = 0, align_to = -1;
int zero_width_ok_p = 0, zero_height_ok_p = 0;
int ascent = 0;
double tem;
struct face *face = FACE_FROM_ID (it->f, it->face_id);
XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
PREPARE_FACE_FOR_DISPLAY (it->f, face);
xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
plist = XCDR (it->object);
if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
&& calc_pixel_width_or_height (&tem, it, prop, font, 1, 0))
{
zero_width_ok_p = 1;
width = (int)tem;
}
else if (prop = Fplist_get (plist, QCrelative_width),
NUMVAL (prop) > 0)
{
struct it it2;
unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
it2 = *it;
if (it->multibyte_p)
{
int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
- IT_BYTEPOS (*it));
it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
}
else
it2.c = *p, it2.len = 1;
it2.glyph_row = NULL;
it2.what = IT_CHARACTER;
x_produce_glyphs (&it2);
width = NUMVAL (prop) * it2.pixel_width;
}
else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
&& calc_pixel_width_or_height (&tem, it, prop, font, 1, &align_to))
{
if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
align_to = (align_to < 0
? 0
: align_to - window_box_left_offset (it->w, TEXT_AREA));
else if (align_to < 0)
align_to = window_box_left_offset (it->w, TEXT_AREA);
width = max (0, (int)tem + align_to - it->current_x);
zero_width_ok_p = 1;
}
else
width = FRAME_COLUMN_WIDTH (it->f);
if (width <= 0 && (width < 0 || !zero_width_ok_p))
width = 1;
if ((prop = Fplist_get (plist, QCheight), !NILP (prop))
&& calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
{
height = (int)tem;
zero_height_ok_p = 1;
}
else if (prop = Fplist_get (plist, QCrelative_height),
NUMVAL (prop) > 0)
height = FONT_HEIGHT (font) * NUMVAL (prop);
else
height = FONT_HEIGHT (font);
if (height <= 0 && (height < 0 || !zero_height_ok_p))
height = 1;
if (prop = Fplist_get (plist, QCascent),
NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
ascent = height * NUMVAL (prop) / 100.0;
else if (!NILP (prop)
&& calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
ascent = min (max (0, (int)tem), height);
else
ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font);
if (width > 0 && !it->truncate_lines_p
&& it->current_x + width > it->last_visible_x)
width = it->last_visible_x - it->current_x - 1;
if (width > 0 && height > 0 && it->glyph_row)
{
Lisp_Object object = it->stack[it->sp - 1].string;
if (!STRINGP (object))
object = it->w->buffer;
append_stretch_glyph (it, object, width, height, ascent);
}
it->pixel_width = width;
it->ascent = it->phys_ascent = ascent;
it->descent = it->phys_descent = height - it->ascent;
it->nglyphs = width > 0 && height > 0 ? 1 : 0;
take_vertical_position_into_account (it);
}
static Lisp_Object
get_line_height_property (it, prop)
struct it *it;
Lisp_Object prop;
{
Lisp_Object position;
if (STRINGP (it->object))
position = make_number (IT_STRING_CHARPOS (*it));
else if (BUFFERP (it->object))
position = make_number (IT_CHARPOS (*it));
else
return Qnil;
return Fget_char_property (position, prop, it->object);
}
static Lisp_Object
calc_line_height_property (it, val, font, boff, override)
struct it *it;
Lisp_Object val;
XFontStruct *font;
int boff, override;
{
Lisp_Object face_name = Qnil;
int ascent, descent, height;
if (NILP (val) || INTEGERP (val) || (override && EQ (val, Qt)))
return val;
if (CONSP (val))
{
face_name = XCAR (val);
val = XCDR (val);
if (!NUMBERP (val))
val = make_number (1);
if (NILP (face_name))
{
height = it->ascent + it->descent;
goto scale;
}
}
if (NILP (face_name))
{
font = FRAME_FONT (it->f);
boff = FRAME_BASELINE_OFFSET (it->f);
}
else if (EQ (face_name, Qt))
{
override = 0;
}
else
{
int face_id;
struct face *face;
struct font_info *font_info;
face_id = lookup_named_face (it->f, face_name, ' ', 0);
if (face_id < 0)
return make_number (-1);
face = FACE_FROM_ID (it->f, face_id);
font = face->font;
if (font == NULL)
return make_number (-1);
font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
boff = font_info->baseline_offset;
if (font_info->vertical_centering)
boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
}
ascent = FONT_BASE (font) + boff;
descent = FONT_DESCENT (font) - boff;
if (override)
{
it->override_ascent = ascent;
it->override_descent = descent;
it->override_boff = boff;
}
height = ascent + descent;
scale:
if (FLOATP (val))
height = (int)(XFLOAT_DATA (val) * height);
else if (INTEGERP (val))
height *= XINT (val);
return make_number (height);
}
void
x_produce_glyphs (it)
struct it *it;
{
int extra_line_spacing = it->extra_line_spacing;
it->glyph_not_available_p = 0;
if (it->what == IT_CHARACTER)
{
XChar2b char2b;
XFontStruct *font;
struct face *face = FACE_FROM_ID (it->f, it->face_id);
XCharStruct *pcm;
int font_not_found_p;
struct font_info *font_info;
int boff;
int saved_multibyte_p = it->multibyte_p;
it->char_to_display = it->c;
if (!ASCII_BYTE_P (it->c))
{
if (unibyte_display_via_language_environment
&& SINGLE_BYTE_CHAR_P (it->c)
&& (it->c >= 0240
|| !NILP (Vnonascii_translation_table)))
{
it->char_to_display = unibyte_char_to_multibyte (it->c);
it->multibyte_p = 1;
it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
face = FACE_FROM_ID (it->f, it->face_id);
}
else if (!SINGLE_BYTE_CHAR_P (it->c)
&& !it->multibyte_p)
{
it->multibyte_p = 1;
it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
face = FACE_FROM_ID (it->f, it->face_id);
}
}
get_char_face_and_encoding (it->f, it->char_to_display, it->face_id,
&char2b, it->multibyte_p, 0);
font = face->font;
font_not_found_p = font == NULL;
if (font_not_found_p)
{
font = FRAME_FONT (it->f);
boff = FRAME_BASELINE_OFFSET (it->f);
font_info = NULL;
}
else
{
font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
boff = font_info->baseline_offset;
if (font_info->vertical_centering)
boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
}
if (it->char_to_display >= ' '
&& (!it->multibyte_p || it->char_to_display < 128))
{
int stretched_p;
it->nglyphs = 1;
pcm = rif->per_char_metric (font, &char2b,
FONT_TYPE_FOR_UNIBYTE (font, it->char_to_display));
if (it->override_ascent >= 0)
{
it->ascent = it->override_ascent;
it->descent = it->override_descent;
boff = it->override_boff;
}
else
{
it->ascent = FONT_BASE (font) + boff;
it->descent = FONT_DESCENT (font) - boff;
}
if (pcm)
{
it->phys_ascent = pcm->ascent + boff;
it->phys_descent = pcm->descent - boff;
it->pixel_width = pcm->width;
}
else
{
it->glyph_not_available_p = 1;
it->phys_ascent = it->ascent;
it->phys_descent = it->descent;
it->pixel_width = FONT_WIDTH (font);
}
if (it->constrain_row_ascent_descent_p)
{
if (it->descent > it->max_descent)
{
it->ascent += it->descent - it->max_descent;
it->descent = it->max_descent;
}
if (it->ascent > it->max_ascent)
{
it->descent = min (it->max_descent, it->descent + it->ascent - it->max_ascent);
it->ascent = it->max_ascent;
}
it->phys_ascent = min (it->phys_ascent, it->ascent);
it->phys_descent = min (it->phys_descent, it->descent);
extra_line_spacing = 0;
}
stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
if (stretched_p)
it->pixel_width *= XFLOATINT (it->space_width);
if (face->box != FACE_NO_BOX)
{
int thick = face->box_line_width;
if (thick > 0)
{
it->ascent += thick;
it->descent += thick;
}
else
thick = -thick;
if (it->start_of_box_run_p)
it->pixel_width += thick;
if (it->end_of_box_run_p)
it->pixel_width += thick;
}
if (face->overline_p)
it->ascent += overline_margin;
if (it->constrain_row_ascent_descent_p)
{
if (it->ascent > it->max_ascent)
it->ascent = it->max_ascent;
if (it->descent > it->max_descent)
it->descent = it->max_descent;
}
take_vertical_position_into_account (it);
if (it->glyph_row)
{
if (stretched_p)
{
int ascent = (((it->ascent + it->descent) * FONT_BASE (font))
/ FONT_HEIGHT (font));
append_stretch_glyph (it, it->object, it->pixel_width,
it->ascent + it->descent, ascent);
}
else
append_glyph (it);
if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
it->glyph_row->contains_overlapping_glyphs_p = 1;
}
}
else if (it->char_to_display == '\n')
{
Lisp_Object height;
Lisp_Object total_height = Qnil;
it->override_ascent = -1;
it->pixel_width = 0;
it->nglyphs = 0;
height = get_line_height_property(it, Qline_height);
if (CONSP (height)
&& CONSP (XCDR (height))
&& NILP (XCDR (XCDR (height))))
{
total_height = XCAR (XCDR (height));
height = XCAR (height);
}
height = calc_line_height_property(it, height, font, boff, 1);
if (it->override_ascent >= 0)
{
it->ascent = it->override_ascent;
it->descent = it->override_descent;
boff = it->override_boff;
}
else
{
it->ascent = FONT_BASE (font) + boff;
it->descent = FONT_DESCENT (font) - boff;
}
if (EQ (height, Qt))
{
if (it->descent > it->max_descent)
{
it->ascent += it->descent - it->max_descent;
it->descent = it->max_descent;
}
if (it->ascent > it->max_ascent)
{
it->descent = min (it->max_descent, it->descent + it->ascent - it->max_ascent);
it->ascent = it->max_ascent;
}
it->phys_ascent = min (it->phys_ascent, it->ascent);
it->phys_descent = min (it->phys_descent, it->descent);
it->constrain_row_ascent_descent_p = 1;
extra_line_spacing = 0;
}
else
{
Lisp_Object spacing;
it->phys_ascent = it->ascent;
it->phys_descent = it->descent;
if ((it->max_ascent > 0 || it->max_descent > 0)
&& face->box != FACE_NO_BOX
&& face->box_line_width > 0)
{
it->ascent += face->box_line_width;
it->descent += face->box_line_width;
}
if (!NILP (height)
&& XINT (height) > it->ascent + it->descent)
it->ascent = XINT (height) - it->descent;
if (!NILP (total_height))
spacing = calc_line_height_property(it, total_height, font, boff, 0);
else
{
spacing = get_line_height_property(it, Qline_spacing);
spacing = calc_line_height_property(it, spacing, font, boff, 0);
}
if (INTEGERP (spacing))
{
extra_line_spacing = XINT (spacing);
if (!NILP (total_height))
extra_line_spacing -= (it->phys_ascent + it->phys_descent);
}
}
}
else if (it->char_to_display == '\t')
{
int tab_width = it->tab_width * FRAME_SPACE_WIDTH (it->f);
int x = it->current_x + it->continuation_lines_width;
int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
if (next_tab_x - x < FRAME_SPACE_WIDTH (it->f))
next_tab_x += tab_width;
it->pixel_width = next_tab_x - x;
it->nglyphs = 1;
it->ascent = it->phys_ascent = FONT_BASE (font) + boff;
it->descent = it->phys_descent = FONT_DESCENT (font) - boff;
if (it->glyph_row)
{
append_stretch_glyph (it, it->object, it->pixel_width,
it->ascent + it->descent, it->ascent);
}
}
else
{
pcm = rif->per_char_metric (font, &char2b,
FONT_TYPE_FOR_MULTIBYTE (font, it->c));
if (font_not_found_p || !pcm)
{
int charset = CHAR_CHARSET (it->char_to_display);
it->glyph_not_available_p = 1;
it->pixel_width = (FRAME_COLUMN_WIDTH (it->f)
* CHARSET_WIDTH (charset));
it->phys_ascent = FONT_BASE (font) + boff;
it->phys_descent = FONT_DESCENT (font) - boff;
}
else
{
it->pixel_width = pcm->width;
it->phys_ascent = pcm->ascent + boff;
it->phys_descent = pcm->descent - boff;
if (it->glyph_row
&& (pcm->lbearing < 0
|| pcm->rbearing > pcm->width))
it->glyph_row->contains_overlapping_glyphs_p = 1;
}
it->nglyphs = 1;
it->ascent = FONT_BASE (font) + boff;
it->descent = FONT_DESCENT (font) - boff;
if (face->box != FACE_NO_BOX)
{
int thick = face->box_line_width;
if (thick > 0)
{
it->ascent += thick;
it->descent += thick;
}
else
thick = - thick;
if (it->start_of_box_run_p)
it->pixel_width += thick;
if (it->end_of_box_run_p)
it->pixel_width += thick;
}
if (face->overline_p)
it->ascent += overline_margin;
take_vertical_position_into_account (it);
if (it->glyph_row)
append_glyph (it);
}
it->multibyte_p = saved_multibyte_p;
}
else if (it->what == IT_COMPOSITION)
{
XChar2b char2b;
XFontStruct *font;
struct face *face = FACE_FROM_ID (it->f, it->face_id);
XCharStruct *pcm;
int font_not_found_p;
struct font_info *font_info;
int boff;
struct composition *cmp = composition_table[it->cmp_id];
it->char_to_display = it->c;
if (unibyte_display_via_language_environment
&& SINGLE_BYTE_CHAR_P (it->c)
&& (it->c >= 0240
|| (it->c >= 0200
&& !NILP (Vnonascii_translation_table))))
{
it->char_to_display = unibyte_char_to_multibyte (it->c);
}
it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
face = FACE_FROM_ID (it->f, it->face_id);
get_char_face_and_encoding (it->f, it->char_to_display, it->face_id,
&char2b, it->multibyte_p, 0);
font = face->font;
font_not_found_p = font == NULL;
if (font_not_found_p)
{
font = FRAME_FONT (it->f);
boff = FRAME_BASELINE_OFFSET (it->f);
font_info = NULL;
}
else
{
font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
boff = font_info->baseline_offset;
if (font_info->vertical_centering)
boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
}
it->nglyphs = 1;
if (cmp->font != (void *) font)
{
int font_ascent = FONT_BASE (font) + boff;
int font_descent = FONT_DESCENT (font) - boff;
int leftmost, rightmost, lowest, highest;
int i, width, ascent, descent;
cmp->font = (void *) font;
if (font_info
&& (pcm = rif->per_char_metric (font, &char2b,
FONT_TYPE_FOR_MULTIBYTE (font, it->c))))
{
width = pcm->width;
ascent = pcm->ascent;
descent = pcm->descent;
}
else
{
width = FONT_WIDTH (font);
ascent = FONT_BASE (font);
descent = FONT_DESCENT (font);
}
rightmost = width;
lowest = - descent + boff;
highest = ascent + boff;
leftmost = 0;
if (font_info
&& font_info->default_ascent
&& CHAR_TABLE_P (Vuse_default_ascent)
&& !NILP (Faref (Vuse_default_ascent,
make_number (it->char_to_display))))
highest = font_info->default_ascent + boff;
cmp->offsets[0] = 0;
cmp->offsets[1] = boff;
for (i = 1; i < cmp->glyph_len; i++)
{
int left, right, btm, top;
int ch = COMPOSITION_GLYPH (cmp, i);
int face_id = FACE_FOR_CHAR (it->f, face, ch);
face = FACE_FROM_ID (it->f, face_id);
get_char_face_and_encoding (it->f, ch, face->id,
&char2b, it->multibyte_p, 0);
font = face->font;
if (font == NULL)
{
font = FRAME_FONT (it->f);
boff = FRAME_BASELINE_OFFSET (it->f);
font_info = NULL;
}
else
{
font_info
= FONT_INFO_FROM_ID (it->f, face->font_info_id);
boff = font_info->baseline_offset;
if (font_info->vertical_centering)
boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
}
if (font_info
&& (pcm = rif->per_char_metric (font, &char2b,
FONT_TYPE_FOR_MULTIBYTE (font, ch))))
{
width = pcm->width;
ascent = pcm->ascent;
descent = pcm->descent;
}
else
{
width = FONT_WIDTH (font);
ascent = 1;
descent = 0;
}
if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
{
left = (leftmost + rightmost - width) / 2;
btm = - descent + boff;
if (font_info && font_info->relative_compose
&& (! CHAR_TABLE_P (Vignore_relative_composition)
|| NILP (Faref (Vignore_relative_composition,
make_number (ch)))))
{
if (- descent >= font_info->relative_compose)
btm = highest + 1;
else if (ascent <= 0)
btm = lowest - 1 - ascent - descent;
}
}
else
{
int rule = COMPOSITION_RULE (cmp, i);
int gref, nref, grefx, grefy, nrefx, nrefy;
COMPOSITION_DECODE_RULE (rule, gref, nref);
grefx = gref % 3, nrefx = nref % 3;
grefy = gref / 3, nrefy = nref / 3;
left = (leftmost
+ grefx * (rightmost - leftmost) / 2
- nrefx * width / 2);
btm = ((grefy == 0 ? highest
: grefy == 1 ? 0
: grefy == 2 ? lowest
: (highest + lowest) / 2)
- (nrefy == 0 ? ascent + descent
: nrefy == 1 ? descent - boff
: nrefy == 2 ? 0
: (ascent + descent) / 2));
}
cmp->offsets[i * 2] = left;
cmp->offsets[i * 2 + 1] = btm + descent;
right = left + width;
top = btm + descent + ascent;
if (left < leftmost)
leftmost = left;
if (right > rightmost)
rightmost = right;
if (top > highest)
highest = top;
if (btm < lowest)
lowest = btm;
}
if (leftmost < 0)
{
for (i = 0; i < cmp->glyph_len; i++)
cmp->offsets[i * 2] -= leftmost;
rightmost -= leftmost;
}
cmp->pixel_width = rightmost;
cmp->ascent = highest;
cmp->descent = - lowest;
if (cmp->ascent < font_ascent)
cmp->ascent = font_ascent;
if (cmp->descent < font_descent)
cmp->descent = font_descent;
}
it->pixel_width = cmp->pixel_width;
it->ascent = it->phys_ascent = cmp->ascent;
it->descent = it->phys_descent = cmp->descent;
if (face->box != FACE_NO_BOX)
{
int thick = face->box_line_width;
if (thick > 0)
{
it->ascent += thick;
it->descent += thick;
}
else
thick = - thick;
if (it->start_of_box_run_p)
it->pixel_width += thick;
if (it->end_of_box_run_p)
it->pixel_width += thick;
}
if (face->overline_p)
it->ascent += overline_margin;
take_vertical_position_into_account (it);
if (it->glyph_row)
append_composite_glyph (it);
}
else if (it->what == IT_IMAGE)
produce_image_glyph (it);
else if (it->what == IT_STRETCH)
produce_stretch_glyph (it);
xassert (it->ascent >= 0 && it->descent >= 0);
if (it->area == TEXT_AREA)
it->current_x += it->pixel_width;
if (extra_line_spacing > 0)
{
it->descent += extra_line_spacing;
if (extra_line_spacing > it->max_extra_line_spacing)
it->max_extra_line_spacing = extra_line_spacing;
}
it->max_ascent = max (it->max_ascent, it->ascent);
it->max_descent = max (it->max_descent, it->descent);
it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
}
void
x_write_glyphs (start, len)
struct glyph *start;
int len;
{
int x, hpos;
xassert (updated_window && updated_row);
BLOCK_INPUT;
hpos = start - updated_row->glyphs[updated_area];
x = draw_glyphs (updated_window, output_cursor.x,
updated_row, updated_area,
hpos, hpos + len,
DRAW_NORMAL_TEXT, 0);
if (updated_area == TEXT_AREA
&& updated_window->phys_cursor_on_p
&& updated_window->phys_cursor.vpos == output_cursor.vpos
&& updated_window->phys_cursor.hpos >= hpos
&& updated_window->phys_cursor.hpos < hpos + len)
updated_window->phys_cursor_on_p = 0;
UNBLOCK_INPUT;
output_cursor.hpos += len;
output_cursor.x = x;
}
void
x_insert_glyphs (start, len)
struct glyph *start;
int len;
{
struct frame *f;
struct window *w;
int line_height, shift_by_width, shifted_region_width;
struct glyph_row *row;
struct glyph *glyph;
int frame_x, frame_y, hpos;
xassert (updated_window && updated_row);
BLOCK_INPUT;
w = updated_window;
f = XFRAME (WINDOW_FRAME (w));
row = updated_row;
line_height = row->height;
shift_by_width = 0;
for (glyph = start; glyph < start + len; ++glyph)
shift_by_width += glyph->pixel_width;
shifted_region_width = (window_box_width (w, updated_area)
- output_cursor.x
- shift_by_width);
frame_x = window_box_left (w, updated_area) + output_cursor.x;
frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
rif->shift_glyphs_for_insert (f, frame_x, frame_y, shifted_region_width,
line_height, shift_by_width);
hpos = start - row->glyphs[updated_area];
draw_glyphs (w, output_cursor.x, row, updated_area,
hpos, hpos + len,
DRAW_NORMAL_TEXT, 0);
output_cursor.hpos += len;
output_cursor.x += shift_by_width;
UNBLOCK_INPUT;
}
void
x_clear_end_of_line (to_x)
int to_x;
{
struct frame *f;
struct window *w = updated_window;
int max_x, min_y, max_y;
int from_x, from_y, to_y;
xassert (updated_window && updated_row);
f = XFRAME (w->frame);
if (updated_row->full_width_p)
max_x = WINDOW_TOTAL_WIDTH (w);
else
max_x = window_box_width (w, updated_area);
max_y = window_text_bottom_y (w);
if (to_x == 0)
return;
else if (to_x < 0)
to_x = max_x;
else
to_x = min (to_x, max_x);
to_y = min (max_y, output_cursor.y + updated_row->height);
if (!updated_row->full_width_p)
notice_overwritten_cursor (w, updated_area,
output_cursor.x, -1,
updated_row->y,
MATRIX_ROW_BOTTOM_Y (updated_row));
from_x = output_cursor.x;
if (updated_row->full_width_p)
{
from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
}
else
{
int area_left = window_box_left (w, updated_area);
from_x += area_left;
to_x += area_left;
}
min_y = WINDOW_HEADER_LINE_HEIGHT (w);
from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
if (to_x > from_x && to_y > from_y)
{
BLOCK_INPUT;
rif->clear_frame_area (f, from_x, from_y,
to_x - from_x, to_y - from_y);
UNBLOCK_INPUT;
}
}
#endif
static enum text_cursor_kinds
get_specified_cursor_type (arg, width)
Lisp_Object arg;
int *width;
{
enum text_cursor_kinds type;
if (NILP (arg))
return NO_CURSOR;
if (EQ (arg, Qbox))
return FILLED_BOX_CURSOR;
if (EQ (arg, Qhollow))
return HOLLOW_BOX_CURSOR;
if (EQ (arg, Qbar))
{
*width = 2;
return BAR_CURSOR;
}
if (CONSP (arg)
&& EQ (XCAR (arg), Qbar)
&& INTEGERP (XCDR (arg))
&& XINT (XCDR (arg)) >= 0)
{
*width = XINT (XCDR (arg));
return BAR_CURSOR;
}
if (EQ (arg, Qhbar))
{
*width = 2;
return HBAR_CURSOR;
}
if (CONSP (arg)
&& EQ (XCAR (arg), Qhbar)
&& INTEGERP (XCDR (arg))
&& XINT (XCDR (arg)) >= 0)
{
*width = XINT (XCDR (arg));
return HBAR_CURSOR;
}
type = HOLLOW_BOX_CURSOR;
return type;
}
void
set_frame_cursor_types (f, arg)
struct frame *f;
Lisp_Object arg;
{
int width;
Lisp_Object tem;
FRAME_DESIRED_CURSOR (f) = get_specified_cursor_type (arg, &width);
FRAME_CURSOR_WIDTH (f) = width;
tem = Fassoc (arg, Vblink_cursor_alist);
if (!NILP (tem))
{
FRAME_BLINK_OFF_CURSOR (f)
= get_specified_cursor_type (XCDR (tem), &width);
FRAME_BLINK_OFF_CURSOR_WIDTH (f) = width;
}
else
FRAME_BLINK_OFF_CURSOR (f) = DEFAULT_CURSOR;
}
static enum text_cursor_kinds
get_window_cursor_type (w, glyph, width, active_cursor)
struct window *w;
struct glyph *glyph;
int *width;
int *active_cursor;
{
struct frame *f = XFRAME (w->frame);
struct buffer *b = XBUFFER (w->buffer);
int cursor_type = DEFAULT_CURSOR;
Lisp_Object alt_cursor;
int non_selected = 0;
*active_cursor = 1;
if (cursor_in_echo_area
&& FRAME_HAS_MINIBUF_P (f)
&& EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
{
if (w == XWINDOW (echo_area_window))
{
if (EQ (b->cursor_type, Qt) || NILP (b->cursor_type))
{
*width = FRAME_CURSOR_WIDTH (f);
return FRAME_DESIRED_CURSOR (f);
}
else
return get_specified_cursor_type (b->cursor_type, width);
}
*active_cursor = 0;
non_selected = 1;
}
else if (w != XWINDOW (f->selected_window)
#ifdef HAVE_WINDOW_SYSTEM
|| f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
#endif
)
{
*active_cursor = 0;
if (MINI_WINDOW_P (w) && minibuf_level == 0)
return NO_CURSOR;
non_selected = 1;
}
if (NILP (b->cursor_type))
return NO_CURSOR;
if (non_selected)
{
alt_cursor = b->cursor_in_non_selected_windows;
return get_specified_cursor_type (alt_cursor, width);
}
if (EQ (b->cursor_type, Qt))
{
cursor_type = FRAME_DESIRED_CURSOR (f);
*width = FRAME_CURSOR_WIDTH (f);
}
else
cursor_type = get_specified_cursor_type (b->cursor_type, width);
if (!w->cursor_off_p)
{
#ifdef HAVE_WINDOW_SYSTEM
if (glyph != NULL && glyph->type == IMAGE_GLYPH)
{
if (cursor_type == FILLED_BOX_CURSOR)
{
struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id);
if (img != NULL && IMAGEP (img->spec))
{
if (!img->mask
|| img->width > max (32, WINDOW_FRAME_COLUMN_WIDTH (w))
|| img->height > max (32, WINDOW_FRAME_LINE_HEIGHT (w)))
cursor_type = HOLLOW_BOX_CURSOR;
}
}
else if (cursor_type != NO_CURSOR)
{
cursor_type = HOLLOW_BOX_CURSOR;
}
}
#endif
return cursor_type;
}
if ((alt_cursor = Fassoc (b->cursor_type, Vblink_cursor_alist), !NILP (alt_cursor)))
return get_specified_cursor_type (XCDR (alt_cursor), width);
if (FRAME_BLINK_OFF_CURSOR (f) != DEFAULT_CURSOR)
{
*width = FRAME_BLINK_OFF_CURSOR_WIDTH (f);
return FRAME_BLINK_OFF_CURSOR (f);
}
#if 0
if (cursor_type == FILLED_BOX_CURSOR)
return HOLLOW_BOX_CURSOR;
if ((cursor_type == BAR_CURSOR || cursor_type == HBAR_CURSOR) && *width > 1)
{
*width = 1;
return cursor_type;
}
#endif
return NO_CURSOR;
}
#ifdef HAVE_WINDOW_SYSTEM
static void
notice_overwritten_cursor (w, area, x0, x1, y0, y1)
struct window *w;
enum glyph_row_area area;
int x0, y0, x1, y1;
{
int cx0, cx1, cy0, cy1;
struct glyph_row *row;
if (!w->phys_cursor_on_p)
return;
if (area != TEXT_AREA)
return;
if (w->phys_cursor.vpos < 0
|| w->phys_cursor.vpos >= w->current_matrix->nrows
|| (row = w->current_matrix->rows + w->phys_cursor.vpos,
!(row->enabled_p && row->displays_text_p)))
return;
if (row->cursor_in_fringe_p)
{
row->cursor_in_fringe_p = 0;
draw_fringe_bitmap (w, row, 0);
w->phys_cursor_on_p = 0;
return;
}
cx0 = w->phys_cursor.x;
cx1 = cx0 + w->phys_cursor_width;
if (x0 > cx0 || (x1 >= 0 && x1 < cx1))
return;
cy0 = w->phys_cursor.y;
cy1 = cy0 + w->phys_cursor_height;
if ((y0 < cy0 || y0 >= cy1) && (y1 <= cy0 || y1 >= cy1))
return;
w->phys_cursor_on_p = 0;
}
#endif
#ifdef HAVE_WINDOW_SYSTEM
void
x_fix_overlapping_area (w, row, area, overlaps)
struct window *w;
struct glyph_row *row;
enum glyph_row_area area;
int overlaps;
{
int i, x;
BLOCK_INPUT;
x = 0;
for (i = 0; i < row->used[area];)
{
if (row->glyphs[area][i].overlaps_vertically_p)
{
int start = i, start_x = x;
do
{
x += row->glyphs[area][i].pixel_width;
++i;
}
while (i < row->used[area]
&& row->glyphs[area][i].overlaps_vertically_p);
draw_glyphs (w, start_x, row, area,
start, i,
DRAW_NORMAL_TEXT, overlaps);
}
else
{
x += row->glyphs[area][i].pixel_width;
++i;
}
}
UNBLOCK_INPUT;
}
void
draw_phys_cursor_glyph (w, row, hl)
struct window *w;
struct glyph_row *row;
enum draw_glyphs_face hl;
{
if (w->phys_cursor.hpos < row->used[TEXT_AREA])
{
int on_p = w->phys_cursor_on_p;
int x1;
x1 = draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
hl, 0);
w->phys_cursor_on_p = on_p;
if (hl == DRAW_CURSOR)
w->phys_cursor_width = x1 - w->phys_cursor.x;
else if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
{
w->phys_cursor_width = x1 - w->phys_cursor.x;
if (row > w->current_matrix->rows
&& MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
x_fix_overlapping_area (w, row - 1, TEXT_AREA,
OVERLAPS_ERASED_CURSOR);
if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
&& MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
x_fix_overlapping_area (w, row + 1, TEXT_AREA,
OVERLAPS_ERASED_CURSOR);
}
}
}
void
erase_phys_cursor (w)
struct window *w;
{
struct frame *f = XFRAME (w->frame);
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
int hpos = w->phys_cursor.hpos;
int vpos = w->phys_cursor.vpos;
int mouse_face_here_p = 0;
struct glyph_matrix *active_glyphs = w->current_matrix;
struct glyph_row *cursor_row;
struct glyph *cursor_glyph;
enum draw_glyphs_face hl;
if (w->phys_cursor_type == NO_CURSOR)
goto mark_cursor_off;
if (vpos >= active_glyphs->nrows)
goto mark_cursor_off;
cursor_row = MATRIX_ROW (active_glyphs, vpos);
if (!cursor_row->enabled_p)
goto mark_cursor_off;
cursor_row->visible_height = min (cursor_row->visible_height,
window_text_bottom_y (w) - cursor_row->y);
if (cursor_row->visible_height <= 0)
goto mark_cursor_off;
if (cursor_row->cursor_in_fringe_p)
{
cursor_row->cursor_in_fringe_p = 0;
draw_fringe_bitmap (w, cursor_row, 0);
goto mark_cursor_off;
}
if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
goto mark_cursor_off;
if (! NILP (dpyinfo->mouse_face_window)
&& w == XWINDOW (dpyinfo->mouse_face_window)
&& (vpos > dpyinfo->mouse_face_beg_row
|| (vpos == dpyinfo->mouse_face_beg_row
&& hpos >= dpyinfo->mouse_face_beg_col))
&& (vpos < dpyinfo->mouse_face_end_row
|| (vpos == dpyinfo->mouse_face_end_row
&& hpos < dpyinfo->mouse_face_end_col))
&& cursor_row->used[TEXT_AREA] > hpos)
mouse_face_here_p = 1;
if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
{
int x, y, left_x;
int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
int width;
cursor_glyph = get_phys_cursor_glyph (w);
if (cursor_glyph == NULL)
goto mark_cursor_off;
width = cursor_glyph->pixel_width;
left_x = window_box_left_offset (w, TEXT_AREA);
x = w->phys_cursor.x;
if (x < left_x)
width -= left_x - x;
width = min (width, window_box_width (w, TEXT_AREA) - x);
y = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, cursor_row->y));
x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, max (x, left_x));
if (width > 0)
rif->clear_frame_area (f, x, y, width, cursor_row->visible_height);
}
if (mouse_face_here_p)
hl = DRAW_MOUSE_FACE;
else
hl = DRAW_NORMAL_TEXT;
draw_phys_cursor_glyph (w, cursor_row, hl);
mark_cursor_off:
w->phys_cursor_on_p = 0;
w->phys_cursor_type = NO_CURSOR;
}
void
display_and_set_cursor (w, on, hpos, vpos, x, y)
struct window *w;
int on, hpos, vpos, x, y;
{
struct frame *f = XFRAME (w->frame);
int new_cursor_type;
int new_cursor_width;
int active_cursor;
struct glyph_row *glyph_row;
struct glyph *glyph;
if (! FRAME_VISIBLE_P (f)
|| FRAME_GARBAGED_P (f)
|| vpos >= w->current_matrix->nrows
|| hpos >= w->current_matrix->matrix_w)
return;
if (!on && !w->phys_cursor_on_p)
return;
glyph_row = MATRIX_ROW (w->current_matrix, vpos);
if (!glyph_row->enabled_p)
{
w->phys_cursor_on_p = 0;
return;
}
glyph = NULL;
if (!glyph_row->exact_window_width_line_p
|| hpos < glyph_row->used[TEXT_AREA])
glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
xassert (interrupt_input_blocked);
new_cursor_type = get_window_cursor_type (w, glyph,
&new_cursor_width, &active_cursor);
if (w->phys_cursor_on_p
&& (!on
|| w->phys_cursor.x != x
|| w->phys_cursor.y != y
|| new_cursor_type != w->phys_cursor_type
|| ((new_cursor_type == BAR_CURSOR || new_cursor_type == HBAR_CURSOR)
&& new_cursor_width != w->phys_cursor_width)))
erase_phys_cursor (w);
if (on)
{
w->phys_cursor_ascent = glyph_row->ascent;
w->phys_cursor_height = glyph_row->height;
w->phys_cursor.x = x;
w->phys_cursor.y = glyph_row->y;
w->phys_cursor.hpos = hpos;
w->phys_cursor.vpos = vpos;
}
rif->draw_window_cursor (w, glyph_row, x, y,
new_cursor_type, new_cursor_width,
on, active_cursor);
}
static void
update_window_cursor (w, on)
struct window *w;
int on;
{
if (w->current_matrix)
{
BLOCK_INPUT;
display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
w->phys_cursor.x, w->phys_cursor.y);
UNBLOCK_INPUT;
}
}
static void
update_cursor_in_window_tree (w, on_p)
struct window *w;
int on_p;
{
while (w)
{
if (!NILP (w->hchild))
update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
else if (!NILP (w->vchild))
update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
else
update_window_cursor (w, on_p);
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
}
void
x_update_cursor (f, on_p)
struct frame *f;
int on_p;
{
update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
}
void
x_clear_cursor (w)
struct window *w;
{
if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
update_window_cursor (w, 0);
}
void
show_mouse_face (dpyinfo, draw)
Display_Info *dpyinfo;
enum draw_glyphs_face draw;
{
struct window *w = XWINDOW (dpyinfo->mouse_face_window);
struct frame *f = XFRAME (WINDOW_FRAME (w));
if (
w->current_matrix != NULL
&& (draw != DRAW_MOUSE_FACE || !dpyinfo->mouse_face_hidden)
&& dpyinfo->mouse_face_end_row < w->current_matrix->nrows)
{
int phys_cursor_on_p = w->phys_cursor_on_p;
struct glyph_row *row, *first, *last;
first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row);
last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row);
for (row = first; row <= last && row->enabled_p; ++row)
{
int start_hpos, end_hpos, start_x;
if (row == first)
{
start_hpos = dpyinfo->mouse_face_beg_col;
start_x = dpyinfo->mouse_face_beg_x;
}
else
{
start_hpos = 0;
start_x = 0;
}
if (row == last)
end_hpos = dpyinfo->mouse_face_end_col;
else
{
end_hpos = row->used[TEXT_AREA];
if (draw == DRAW_NORMAL_TEXT)
row->fill_line_p = 1;
}
if (end_hpos > start_hpos)
{
draw_glyphs (w, start_x, row, TEXT_AREA,
start_hpos, end_hpos,
draw, 0);
row->mouse_face_p
= draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED;
}
}
if (phys_cursor_on_p && !w->phys_cursor_on_p)
{
BLOCK_INPUT;
display_and_set_cursor (w, 1,
w->phys_cursor.hpos, w->phys_cursor.vpos,
w->phys_cursor.x, w->phys_cursor.y);
UNBLOCK_INPUT;
}
}
if (draw == DRAW_NORMAL_TEXT && !EQ (dpyinfo->mouse_face_window, f->tool_bar_window))
rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->text_cursor);
else if (draw == DRAW_MOUSE_FACE)
rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->hand_cursor);
else
rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->nontext_cursor);
}
int
clear_mouse_face (dpyinfo)
Display_Info *dpyinfo;
{
int cleared = 0;
if (!dpyinfo->mouse_face_hidden && !NILP (dpyinfo->mouse_face_window))
{
show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
cleared = 1;
}
dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
dpyinfo->mouse_face_window = Qnil;
dpyinfo->mouse_face_overlay = Qnil;
return cleared;
}
int
cursor_in_mouse_face_p (w)
struct window *w;
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
int in_mouse_face = 0;
if (WINDOWP (dpyinfo->mouse_face_window)
&& XWINDOW (dpyinfo->mouse_face_window) == w)
{
int hpos = w->phys_cursor.hpos;
int vpos = w->phys_cursor.vpos;
if (vpos >= dpyinfo->mouse_face_beg_row
&& vpos <= dpyinfo->mouse_face_end_row
&& (vpos > dpyinfo->mouse_face_beg_row
|| hpos >= dpyinfo->mouse_face_beg_col)
&& (vpos < dpyinfo->mouse_face_end_row
|| hpos < dpyinfo->mouse_face_end_col
|| dpyinfo->mouse_face_past_end))
in_mouse_face = 1;
}
return in_mouse_face;
}
#if 1
static int
fast_find_position (w, charpos, hpos, vpos, x, y, stop)
struct window *w;
int charpos;
int *hpos, *vpos, *x, *y;
Lisp_Object stop;
{
struct glyph_row *row, *first;
struct glyph *glyph, *end;
int past_end = 0;
first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
if (charpos < MATRIX_ROW_START_CHARPOS (first))
{
*x = first->x;
*y = first->y;
*hpos = 0;
*vpos = MATRIX_ROW_VPOS (first, w->current_matrix);
return 1;
}
row = row_containing_pos (w, charpos, first, NULL, 0);
if (row == NULL)
{
row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
past_end = 1;
}
if (!NILP (stop))
{
struct glyph_row *prev;
while ((prev = row - 1, prev >= first)
&& MATRIX_ROW_END_CHARPOS (prev) == charpos
&& prev->used[TEXT_AREA] > 0)
{
struct glyph *beg = prev->glyphs[TEXT_AREA];
glyph = beg + prev->used[TEXT_AREA];
while (--glyph >= beg
&& INTEGERP (glyph->object));
if (glyph < beg
|| !EQ (stop, glyph->object))
break;
row = prev;
}
}
*x = row->x;
*y = row->y;
*vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
glyph = row->glyphs[TEXT_AREA];
end = glyph + row->used[TEXT_AREA];
if (row->displays_text_p)
while (glyph < end
&& INTEGERP (glyph->object)
&& !EQ (stop, glyph->object)
&& glyph->charpos < 0)
{
*x += glyph->pixel_width;
++glyph;
}
while (glyph < end
&& !INTEGERP (glyph->object)
&& !EQ (stop, glyph->object)
&& (!BUFFERP (glyph->object)
|| glyph->charpos < charpos))
{
*x += glyph->pixel_width;
++glyph;
}
*hpos = glyph - row->glyphs[TEXT_AREA];
return !past_end;
}
#else
static int
fast_find_position (w, pos, hpos, vpos, x, y, stop)
struct window *w;
int pos;
int *hpos, *vpos, *x, *y;
Lisp_Object stop;
{
int i;
int lastcol;
int maybe_next_line_p = 0;
int line_start_position;
int yb = window_text_bottom_y (w);
struct glyph_row *row, *best_row;
int row_vpos, best_row_vpos;
int current_x;
row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
while (row->y < yb)
{
if (row->used[TEXT_AREA])
line_start_position = row->glyphs[TEXT_AREA]->charpos;
else
line_start_position = 0;
if (line_start_position > pos)
break;
else if (line_start_position == pos
&& pos == BUF_ZV (XBUFFER (w->buffer)))
{
maybe_next_line_p = 1;
break;
}
else if (line_start_position > 0)
{
best_row = row;
best_row_vpos = row_vpos;
}
if (row->y + row->height >= yb)
break;
++row;
++row_vpos;
}
lastcol = 0;
current_x = best_row->x;
for (i = 0; i < best_row->used[TEXT_AREA]; i++)
{
struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
int charpos = glyph->charpos;
if (BUFFERP (glyph->object))
{
if (charpos == pos)
{
*hpos = i;
*vpos = best_row_vpos;
*x = current_x;
*y = best_row->y;
return 1;
}
else if (charpos > pos)
break;
}
else if (EQ (glyph->object, stop))
break;
if (charpos > 0)
lastcol = i;
current_x += glyph->pixel_width;
}
if (maybe_next_line_p)
{
++best_row;
++best_row_vpos;
lastcol = 0;
current_x = best_row->x;
}
*vpos = best_row_vpos;
*hpos = lastcol + 1;
*x = current_x;
*y = best_row->y;
return 0;
}
#endif
static int
fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
struct window *w;
int pos;
Lisp_Object object;
int *hpos, *vpos, *x, *y;
int right_p;
{
int yb = window_text_bottom_y (w);
struct glyph_row *r;
struct glyph *best_glyph = NULL;
struct glyph_row *best_row = NULL;
int best_x = 0;
for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
r->enabled_p && r->y < yb;
++r)
{
struct glyph *g = r->glyphs[TEXT_AREA];
struct glyph *e = g + r->used[TEXT_AREA];
int gx;
for (gx = r->x; g < e; gx += g->pixel_width, ++g)
if (EQ (g->object, object))
{
if (g->charpos == pos)
{
best_glyph = g;
best_x = gx;
best_row = r;
goto found;
}
else if (best_glyph == NULL
|| ((abs (g->charpos - pos)
< abs (best_glyph->charpos - pos))
&& (right_p
? g->charpos < pos
: g->charpos > pos)))
{
best_glyph = g;
best_x = gx;
best_row = r;
}
}
}
found:
if (best_glyph)
{
*x = best_x;
*hpos = best_glyph - best_row->glyphs[TEXT_AREA];
if (right_p)
{
*x += best_glyph->pixel_width;
++*hpos;
}
*y = best_row->y;
*vpos = best_row - w->current_matrix->rows;
}
return best_glyph != NULL;
}
static int
on_hot_spot_p (hot_spot, x, y)
Lisp_Object hot_spot;
int x, y;
{
if (!CONSP (hot_spot))
return 0;
if (EQ (XCAR (hot_spot), Qrect))
{
Lisp_Object rect = XCDR (hot_spot);
Lisp_Object tem;
if (!CONSP (rect))
return 0;
if (!CONSP (XCAR (rect)))
return 0;
if (!CONSP (XCDR (rect)))
return 0;
if (!(tem = XCAR (XCAR (rect)), INTEGERP (tem) && x >= XINT (tem)))
return 0;
if (!(tem = XCDR (XCAR (rect)), INTEGERP (tem) && y >= XINT (tem)))
return 0;
if (!(tem = XCAR (XCDR (rect)), INTEGERP (tem) && x <= XINT (tem)))
return 0;
if (!(tem = XCDR (XCDR (rect)), INTEGERP (tem) && y <= XINT (tem)))
return 0;
return 1;
}
else if (EQ (XCAR (hot_spot), Qcircle))
{
Lisp_Object circ = XCDR (hot_spot);
Lisp_Object lr, lx0, ly0;
if (CONSP (circ)
&& CONSP (XCAR (circ))
&& (lr = XCDR (circ), INTEGERP (lr) || FLOATP (lr))
&& (lx0 = XCAR (XCAR (circ)), INTEGERP (lx0))
&& (ly0 = XCDR (XCAR (circ)), INTEGERP (ly0)))
{
double r = XFLOATINT (lr);
double dx = XINT (lx0) - x;
double dy = XINT (ly0) - y;
return (dx * dx + dy * dy <= r * r);
}
}
else if (EQ (XCAR (hot_spot), Qpoly))
{
if (VECTORP (XCDR (hot_spot)))
{
struct Lisp_Vector *v = XVECTOR (XCDR (hot_spot));
Lisp_Object *poly = v->contents;
int n = v->size;
int i;
int inside = 0;
Lisp_Object lx, ly;
int x0, y0;
if (n < 6 || n & 1)
return 0;
if ((lx = poly[n-2], !INTEGERP (lx))
|| (ly = poly[n-1], !INTEGERP (lx)))
return 0;
x0 = XINT (lx), y0 = XINT (ly);
for (i = 0; i < n; i += 2)
{
int x1 = x0, y1 = y0;
if ((lx = poly[i], !INTEGERP (lx))
|| (ly = poly[i+1], !INTEGERP (ly)))
return 0;
x0 = XINT (lx), y0 = XINT (ly);
if (x0 >= x)
{
if (x1 >= x)
continue;
}
else if (x1 < x)
continue;
if (y > y0 && y > y1)
continue;
if (y < y0 + ((y1 - y0) * (x - x0)) / (x1 - x0))
inside = !inside;
}
return inside;
}
}
return 0;
}
Lisp_Object
find_hot_spot (map, x, y)
Lisp_Object map;
int x, y;
{
while (CONSP (map))
{
if (CONSP (XCAR (map))
&& on_hot_spot_p (XCAR (XCAR (map)), x, y))
return XCAR (map);
map = XCDR (map);
}
return Qnil;
}
DEFUN ("lookup-image-map", Flookup_image_map, Slookup_image_map,
3, 3, 0,
doc: )
(map, x, y)
Lisp_Object map;
Lisp_Object x, y;
{
if (NILP (map))
return Qnil;
CHECK_NUMBER (x);
CHECK_NUMBER (y);
return find_hot_spot (map, XINT (x), XINT (y));
}
static void
define_frame_cursor1 (f, cursor, pointer)
struct frame *f;
Cursor cursor;
Lisp_Object pointer;
{
if (!NILP (do_mouse_tracking))
return;
if (!NILP (pointer))
{
if (EQ (pointer, Qarrow))
cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
else if (EQ (pointer, Qhand))
cursor = FRAME_X_OUTPUT (f)->hand_cursor;
else if (EQ (pointer, Qtext))
cursor = FRAME_X_OUTPUT (f)->text_cursor;
else if (EQ (pointer, intern ("hdrag")))
cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
#ifdef HAVE_X_WINDOWS
else if (EQ (pointer, intern ("vdrag")))
cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
#endif
else if (EQ (pointer, intern ("hourglass")))
cursor = FRAME_X_OUTPUT (f)->hourglass_cursor;
else if (EQ (pointer, Qmodeline))
cursor = FRAME_X_OUTPUT (f)->modeline_cursor;
else
cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
}
if (cursor != No_Cursor)
rif->define_frame_cursor (f, cursor);
}
static void
note_mode_line_or_margin_highlight (window, x, y, area)
Lisp_Object window;
int x, y;
enum window_part area;
{
struct window *w = XWINDOW (window);
struct frame *f = XFRAME (w->frame);
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
Cursor cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
Lisp_Object pointer = Qnil;
int charpos, dx, dy, width, height;
Lisp_Object string, object = Qnil;
Lisp_Object pos, help;
Lisp_Object mouse_face;
int original_x_pixel = x;
struct glyph * glyph = NULL, * row_start_glyph = NULL;
struct glyph_row *row;
if (area == ON_MODE_LINE || area == ON_HEADER_LINE)
{
int x0;
struct glyph *end;
string = mode_line_string (w, area, &x, &y, &charpos,
&object, &dx, &dy, &width, &height);
row = (area == ON_MODE_LINE
? MATRIX_MODE_LINE_ROW (w->current_matrix)
: MATRIX_HEADER_LINE_ROW (w->current_matrix));
if (row->mode_line_p && row->enabled_p)
{
glyph = row_start_glyph = row->glyphs[TEXT_AREA];
end = glyph + row->used[TEXT_AREA];
for (x0 = original_x_pixel;
glyph < end && x0 >= glyph->pixel_width;
++glyph)
x0 -= glyph->pixel_width;
if (glyph >= end)
glyph = NULL;
}
}
else
{
x -= WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w);
string = marginal_area_string (w, area, &x, &y, &charpos,
&object, &dx, &dy, &width, &height);
}
help = Qnil;
if (IMAGEP (object))
{
Lisp_Object image_map, hotspot;
if ((image_map = Fplist_get (XCDR (object), QCmap),
!NILP (image_map))
&& (hotspot = find_hot_spot (image_map, dx, dy),
CONSP (hotspot))
&& (hotspot = XCDR (hotspot), CONSP (hotspot)))
{
Lisp_Object area_id, plist;
area_id = XCAR (hotspot);
hotspot = XCDR (hotspot);
if (CONSP (hotspot)
&& (plist = XCAR (hotspot), CONSP (plist)))
{
pointer = Fplist_get (plist, Qpointer);
if (NILP (pointer))
pointer = Qhand;
help = Fplist_get (plist, Qhelp_echo);
if (!NILP (help))
{
help_echo_string = help;
XSETWINDOW (help_echo_window, w);
help_echo_object = w->buffer;
help_echo_pos = charpos;
}
}
}
if (NILP (pointer))
pointer = Fplist_get (XCDR (object), QCpointer);
}
if (STRINGP (string))
{
pos = make_number (charpos);
if (NILP (help))
{
help = Fget_text_property (pos, Qhelp_echo, string);
if (!NILP (help))
{
help_echo_string = help;
XSETWINDOW (help_echo_window, w);
help_echo_object = string;
help_echo_pos = charpos;
}
}
if (NILP (pointer))
pointer = Fget_text_property (pos, Qpointer, string);
if (NILP (pointer) && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE)))
{
Lisp_Object map;
map = Fget_text_property (pos, Qlocal_map, string);
if (!KEYMAPP (map))
map = Fget_text_property (pos, Qkeymap, string);
if (!KEYMAPP (map))
cursor = dpyinfo->vertical_scroll_bar_cursor;
}
mouse_face = Fget_text_property (pos, Qmouse_face, string);
if (!NILP (mouse_face)
&& ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))
&& glyph)
{
Lisp_Object b, e;
struct glyph * tmp_glyph;
int gpos;
int gseq_length;
int total_pixel_width;
int ignore;
int vpos, hpos;
b = Fprevious_single_property_change (make_number (charpos + 1),
Qmouse_face, string, Qnil);
if (NILP (b))
b = make_number (0);
e = Fnext_single_property_change (pos, Qmouse_face, string, Qnil);
if (NILP (e))
e = make_number (SCHARS (string));
gpos = 0;
if (glyph > row_start_glyph)
{
tmp_glyph = glyph - 1;
while (tmp_glyph >= row_start_glyph
&& tmp_glyph->charpos >= XINT (b)
&& EQ (tmp_glyph->object, glyph->object))
{
tmp_glyph--;
gpos++;
}
}
for (tmp_glyph = glyph, gseq_length = gpos;
tmp_glyph->charpos < XINT (e);
tmp_glyph++, gseq_length++)
{
if (!EQ (tmp_glyph->object, glyph->object))
break;
}
total_pixel_width = 0;
for (tmp_glyph = glyph - gpos; tmp_glyph != glyph; tmp_glyph++)
total_pixel_width += tmp_glyph->pixel_width;
vpos = (x - gpos);
hpos = (area == ON_MODE_LINE
? (w->current_matrix)->nrows - 1
: 0);
if ( EQ (window, dpyinfo->mouse_face_window)
&& dpyinfo->mouse_face_beg_col <= vpos
&& vpos < dpyinfo->mouse_face_end_col
&& dpyinfo->mouse_face_beg_row == hpos )
return;
if (clear_mouse_face (dpyinfo))
cursor = No_Cursor;
dpyinfo->mouse_face_beg_col = vpos;
dpyinfo->mouse_face_beg_row = hpos;
dpyinfo->mouse_face_beg_x = original_x_pixel - (total_pixel_width + dx);
dpyinfo->mouse_face_beg_y = 0;
dpyinfo->mouse_face_end_col = vpos + gseq_length;
dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_beg_row;
dpyinfo->mouse_face_end_x = 0;
dpyinfo->mouse_face_end_y = 0;
dpyinfo->mouse_face_past_end = 0;
dpyinfo->mouse_face_window = window;
dpyinfo->mouse_face_face_id = face_at_string_position (w, string,
charpos,
0, 0, 0, &ignore,
glyph->face_id, 1);
show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
if (NILP (pointer))
pointer = Qhand;
}
else if ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))
clear_mouse_face (dpyinfo);
}
define_frame_cursor1 (f, cursor, pointer);
}
void
note_mouse_highlight (f, x, y)
struct frame *f;
int x, y;
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
enum window_part part;
Lisp_Object window;
struct window *w;
Cursor cursor = No_Cursor;
Lisp_Object pointer = Qnil;
struct buffer *b;
#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (MAC_OS)
if (popup_activated ())
return;
#endif
if (NILP (Vmouse_highlight)
|| !f->glyphs_initialized_p)
return;
dpyinfo->mouse_face_mouse_x = x;
dpyinfo->mouse_face_mouse_y = y;
dpyinfo->mouse_face_mouse_frame = f;
if (dpyinfo->mouse_face_defer)
return;
if (gc_in_progress)
{
dpyinfo->mouse_face_deferred_gc = 1;
return;
}
window = window_from_coordinates (f, x, y, &part, 0, 0, 1);
if (! EQ (window, dpyinfo->mouse_face_window)
|| (part != ON_TEXT && part != ON_MODE_LINE && part != ON_HEADER_LINE
&& !NILP (dpyinfo->mouse_face_window)))
clear_mouse_face (dpyinfo);
if (!WINDOWP (window))
return;
help_echo_string = Qnil;
w = XWINDOW (window);
frame_to_window_pixel_xy (w, &x, &y);
if (EQ (window, f->tool_bar_window))
{
note_tool_bar_highlight (f, x, y);
return;
}
if (part == ON_MODE_LINE || part == ON_HEADER_LINE
|| part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
{
note_mode_line_or_margin_highlight (window, x, y, part);
return;
}
if (part == ON_VERTICAL_BORDER)
{
cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
help_echo_string = build_string ("drag-mouse-1: resize");
}
else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE
|| part == ON_SCROLL_BAR)
cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
else
cursor = FRAME_X_OUTPUT (f)->text_cursor;
b = XBUFFER (w->buffer);
if (part == ON_TEXT
&& EQ (w->window_end_valid, w->buffer)
&& XFASTINT (w->last_modified) == BUF_MODIFF (b)
&& XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
{
int hpos, vpos, pos, i, dx, dy, area;
struct glyph *glyph;
Lisp_Object object;
Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
Lisp_Object *overlay_vec = NULL;
int noverlays;
struct buffer *obuf;
int obegv, ozv, same_region;
glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &dx, &dy, &area);
if (glyph != NULL && glyph->type == IMAGE_GLYPH)
{
struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id);
if (img != NULL && IMAGEP (img->spec))
{
Lisp_Object image_map, hotspot;
if ((image_map = Fplist_get (XCDR (img->spec), QCmap),
!NILP (image_map))
&& (hotspot = find_hot_spot (image_map,
glyph->slice.x + dx,
glyph->slice.y + dy),
CONSP (hotspot))
&& (hotspot = XCDR (hotspot), CONSP (hotspot)))
{
Lisp_Object area_id, plist;
area_id = XCAR (hotspot);
hotspot = XCDR (hotspot);
if (CONSP (hotspot)
&& (plist = XCAR (hotspot), CONSP (plist)))
{
pointer = Fplist_get (plist, Qpointer);
if (NILP (pointer))
pointer = Qhand;
help_echo_string = Fplist_get (plist, Qhelp_echo);
if (!NILP (help_echo_string))
{
help_echo_window = window;
help_echo_object = glyph->object;
help_echo_pos = glyph->charpos;
}
}
}
if (NILP (pointer))
pointer = Fplist_get (XCDR (img->spec), QCpointer);
}
}
if (glyph == NULL
|| area != TEXT_AREA
|| !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
{
if (clear_mouse_face (dpyinfo))
cursor = No_Cursor;
if (NILP (pointer))
{
if (area != TEXT_AREA)
cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
else
pointer = Vvoid_text_area_pointer;
}
goto set_cursor;
}
pos = glyph->charpos;
object = glyph->object;
if (!STRINGP (object) && !BUFFERP (object))
goto set_cursor;
if (BUFFERP (object) && pos > BUF_Z (b))
goto set_cursor;
obuf = current_buffer;
current_buffer = b;
obegv = BEGV;
ozv = ZV;
BEGV = BEG;
ZV = Z;
position = make_number (pos);
if (BUFFERP (object))
{
GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
noverlays = sort_overlays (overlay_vec, noverlays, w);
}
else
noverlays = 0;
same_region = (EQ (window, dpyinfo->mouse_face_window)
&& vpos >= dpyinfo->mouse_face_beg_row
&& vpos <= dpyinfo->mouse_face_end_row
&& (vpos > dpyinfo->mouse_face_beg_row
|| hpos >= dpyinfo->mouse_face_beg_col)
&& (vpos < dpyinfo->mouse_face_end_row
|| hpos < dpyinfo->mouse_face_end_col
|| dpyinfo->mouse_face_past_end));
if (same_region)
cursor = No_Cursor;
if (! same_region
|| (OVERLAYP (dpyinfo->mouse_face_overlay)
&& mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
{
overlay = Qnil;
for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
{
mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
if (!NILP (mouse_face))
overlay = overlay_vec[i];
}
if (!NILP (overlay)
&& EQ (overlay, dpyinfo->mouse_face_overlay))
goto check_help_echo;
dpyinfo->mouse_face_overlay = overlay;
if (clear_mouse_face (dpyinfo))
cursor = No_Cursor;
if (NILP (overlay))
mouse_face = Fget_text_property (position, Qmouse_face, object);
if (!NILP (overlay))
{
Lisp_Object before, after;
int ignore;
before = Foverlay_start (overlay);
after = Foverlay_end (overlay);
fast_find_position (w, XFASTINT (before),
&dpyinfo->mouse_face_beg_col,
&dpyinfo->mouse_face_beg_row,
&dpyinfo->mouse_face_beg_x,
&dpyinfo->mouse_face_beg_y, Qnil);
dpyinfo->mouse_face_past_end
= !fast_find_position (w, XFASTINT (after),
&dpyinfo->mouse_face_end_col,
&dpyinfo->mouse_face_end_row,
&dpyinfo->mouse_face_end_x,
&dpyinfo->mouse_face_end_y, Qnil);
dpyinfo->mouse_face_window = window;
dpyinfo->mouse_face_face_id
= face_at_buffer_position (w, pos, 0, 0,
&ignore, pos + 1,
!dpyinfo->mouse_face_hidden);
show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
cursor = No_Cursor;
}
else if (!NILP (mouse_face) && BUFFERP (object))
{
Lisp_Object before, after, beginning, end;
int ignore;
beginning = Fmarker_position (w->start);
end = make_number (BUF_Z (XBUFFER (object))
- XFASTINT (w->window_end_pos));
before
= Fprevious_single_property_change (make_number (pos + 1),
Qmouse_face,
object, beginning);
after
= Fnext_single_property_change (position, Qmouse_face,
object, end);
fast_find_position (w, XFASTINT (before),
&dpyinfo->mouse_face_beg_col,
&dpyinfo->mouse_face_beg_row,
&dpyinfo->mouse_face_beg_x,
&dpyinfo->mouse_face_beg_y, Qnil);
dpyinfo->mouse_face_past_end
= !fast_find_position (w, XFASTINT (after),
&dpyinfo->mouse_face_end_col,
&dpyinfo->mouse_face_end_row,
&dpyinfo->mouse_face_end_x,
&dpyinfo->mouse_face_end_y, Qnil);
dpyinfo->mouse_face_window = window;
if (BUFFERP (object))
dpyinfo->mouse_face_face_id
= face_at_buffer_position (w, pos, 0, 0,
&ignore, pos + 1,
!dpyinfo->mouse_face_hidden);
show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
cursor = No_Cursor;
}
else if (!NILP (mouse_face) && STRINGP (object))
{
Lisp_Object b, e;
int ignore;
b = Fprevious_single_property_change (make_number (pos + 1),
Qmouse_face,
object, Qnil);
e = Fnext_single_property_change (position, Qmouse_face,
object, Qnil);
if (NILP (b))
b = make_number (0);
if (NILP (e))
e = make_number (SCHARS (object) - 1);
fast_find_string_pos (w, XINT (b), object,
&dpyinfo->mouse_face_beg_col,
&dpyinfo->mouse_face_beg_row,
&dpyinfo->mouse_face_beg_x,
&dpyinfo->mouse_face_beg_y, 0);
fast_find_string_pos (w, XINT (e), object,
&dpyinfo->mouse_face_end_col,
&dpyinfo->mouse_face_end_row,
&dpyinfo->mouse_face_end_x,
&dpyinfo->mouse_face_end_y, 1);
dpyinfo->mouse_face_past_end = 0;
dpyinfo->mouse_face_window = window;
dpyinfo->mouse_face_face_id
= face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
glyph->face_id, 1);
show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
cursor = No_Cursor;
}
else if (STRINGP (object) && NILP (mouse_face))
{
struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
int start = MATRIX_ROW_START_CHARPOS (r);
pos = string_buffer_position (w, object, start);
if (pos > 0)
mouse_face = get_char_property_and_overlay (make_number (pos),
Qmouse_face,
w->buffer,
&overlay);
if (!NILP (mouse_face) && !NILP (overlay))
{
Lisp_Object before = Foverlay_start (overlay);
Lisp_Object after = Foverlay_end (overlay);
int ignore;
fast_find_position (w, XFASTINT (before),
&dpyinfo->mouse_face_beg_col,
&dpyinfo->mouse_face_beg_row,
&dpyinfo->mouse_face_beg_x,
&dpyinfo->mouse_face_beg_y,
object);
dpyinfo->mouse_face_past_end
= !fast_find_position (w, XFASTINT (after),
&dpyinfo->mouse_face_end_col,
&dpyinfo->mouse_face_end_row,
&dpyinfo->mouse_face_end_x,
&dpyinfo->mouse_face_end_y,
Qnil);
dpyinfo->mouse_face_window = window;
dpyinfo->mouse_face_face_id
= face_at_buffer_position (w, pos, 0, 0,
&ignore, pos + 1,
!dpyinfo->mouse_face_hidden);
show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
cursor = No_Cursor;
}
}
}
check_help_echo:
if (NILP (help_echo_string)) {
Lisp_Object help, overlay;
help = overlay = Qnil;
for (i = noverlays - 1; i >= 0 && NILP (help); --i)
{
overlay = overlay_vec[i];
help = Foverlay_get (overlay, Qhelp_echo);
}
if (!NILP (help))
{
help_echo_string = help;
help_echo_window = window;
help_echo_object = overlay;
help_echo_pos = pos;
}
else
{
Lisp_Object object = glyph->object;
int charpos = glyph->charpos;
if (STRINGP (object)
&& charpos >= 0
&& charpos < SCHARS (object))
{
help = Fget_text_property (make_number (charpos),
Qhelp_echo, object);
if (NILP (help))
{
struct glyph_row *r
= MATRIX_ROW (w->current_matrix, vpos);
int start = MATRIX_ROW_START_CHARPOS (r);
int pos = string_buffer_position (w, object, start);
if (pos > 0)
{
help = Fget_char_property (make_number (pos),
Qhelp_echo, w->buffer);
if (!NILP (help))
{
charpos = pos;
object = w->buffer;
}
}
}
}
else if (BUFFERP (object)
&& charpos >= BEGV
&& charpos < ZV)
help = Fget_text_property (make_number (charpos), Qhelp_echo,
object);
if (!NILP (help))
{
help_echo_string = help;
help_echo_window = window;
help_echo_object = object;
help_echo_pos = charpos;
}
}
}
if (NILP (pointer))
{
for (i = noverlays - 1; i >= 0 && NILP (pointer); --i)
pointer = Foverlay_get (overlay_vec[i], Qpointer);
if (NILP (pointer))
{
Lisp_Object object = glyph->object;
int charpos = glyph->charpos;
if (STRINGP (object)
&& charpos >= 0
&& charpos < SCHARS (object))
{
pointer = Fget_text_property (make_number (charpos),
Qpointer, object);
if (NILP (pointer))
{
struct glyph_row *r
= MATRIX_ROW (w->current_matrix, vpos);
int start = MATRIX_ROW_START_CHARPOS (r);
int pos = string_buffer_position (w, object, start);
if (pos > 0)
pointer = Fget_char_property (make_number (pos),
Qpointer, w->buffer);
}
}
else if (BUFFERP (object)
&& charpos >= BEGV
&& charpos < ZV)
pointer = Fget_text_property (make_number (charpos),
Qpointer, object);
}
}
BEGV = obegv;
ZV = ozv;
current_buffer = obuf;
}
set_cursor:
define_frame_cursor1 (f, cursor, pointer);
}
void
x_clear_window_mouse_face (w)
struct window *w;
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
Lisp_Object window;
BLOCK_INPUT;
XSETWINDOW (window, w);
if (EQ (window, dpyinfo->mouse_face_window))
clear_mouse_face (dpyinfo);
UNBLOCK_INPUT;
}
void
cancel_mouse_face (f)
struct frame *f;
{
Lisp_Object window;
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
window = dpyinfo->mouse_face_window;
if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
{
dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
dpyinfo->mouse_face_window = Qnil;
}
}
#endif
#ifdef HAVE_WINDOW_SYSTEM
static void
expose_area (w, row, r, area)
struct window *w;
struct glyph_row *row;
XRectangle *r;
enum glyph_row_area area;
{
struct glyph *first = row->glyphs[area];
struct glyph *end = row->glyphs[area] + row->used[area];
struct glyph *last;
int first_x, start_x, x;
if (area == TEXT_AREA && row->fill_line_p)
draw_glyphs (w, 0, row, area,
0, row->used[area],
DRAW_NORMAL_TEXT, 0);
else
{
start_x = window_box_left_offset (w, area);
x = start_x;
if (area == TEXT_AREA)
x += row->x;
while (first < end
&& x + first->pixel_width < r->x)
{
x += first->pixel_width;
++first;
}
last = first;
first_x = x;
while (last < end
&& x < r->x + r->width)
{
x += last->pixel_width;
++last;
}
if (last > first)
draw_glyphs (w, first_x - start_x, row, area,
first - row->glyphs[area], last - row->glyphs[area],
DRAW_NORMAL_TEXT, 0);
}
}
static int
expose_line (w, row, r)
struct window *w;
struct glyph_row *row;
XRectangle *r;
{
xassert (row->enabled_p);
if (row->mode_line_p || w->pseudo_window_p)
draw_glyphs (w, 0, row, TEXT_AREA,
0, row->used[TEXT_AREA],
DRAW_NORMAL_TEXT, 0);
else
{
if (row->used[LEFT_MARGIN_AREA])
expose_area (w, row, r, LEFT_MARGIN_AREA);
if (row->used[TEXT_AREA])
expose_area (w, row, r, TEXT_AREA);
if (row->used[RIGHT_MARGIN_AREA])
expose_area (w, row, r, RIGHT_MARGIN_AREA);
draw_row_fringe_bitmaps (w, row);
}
return row->mouse_face_p;
}
static void
expose_overlaps (w, first_overlapping_row, last_overlapping_row)
struct window *w;
struct glyph_row *first_overlapping_row;
struct glyph_row *last_overlapping_row;
{
struct glyph_row *row;
for (row = first_overlapping_row; row <= last_overlapping_row; ++row)
if (row->overlapping_p)
{
xassert (row->enabled_p && !row->mode_line_p);
if (row->used[LEFT_MARGIN_AREA])
x_fix_overlapping_area (w, row, LEFT_MARGIN_AREA, OVERLAPS_BOTH);
if (row->used[TEXT_AREA])
x_fix_overlapping_area (w, row, TEXT_AREA, OVERLAPS_BOTH);
if (row->used[RIGHT_MARGIN_AREA])
x_fix_overlapping_area (w, row, RIGHT_MARGIN_AREA, OVERLAPS_BOTH);
}
}
static int
phys_cursor_in_rect_p (w, r)
struct window *w;
XRectangle *r;
{
XRectangle cr, result;
struct glyph *cursor_glyph;
cursor_glyph = get_phys_cursor_glyph (w);
if (cursor_glyph)
{
cr.x = window_box_left_offset (w, TEXT_AREA) + w->phys_cursor.x;
cr.y = w->phys_cursor.y;
cr.width = cursor_glyph->pixel_width;
cr.height = w->phys_cursor_height;
return x_intersect_rectangles (&cr, r, &result);
}
else
return 0;
}
void
x_draw_vertical_border (w)
struct window *w;
{
if (FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (w->frame)))
return;
if (!WINDOW_RIGHTMOST_P (w)
&& !WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
{
int x0, x1, y0, y1;
window_box_edges (w, -1, &x0, &y0, &x1, &y1);
y1 -= 1;
if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
x1 -= 1;
rif->draw_vertical_window_border (w, x1, y0, y1);
}
else if (!WINDOW_LEFTMOST_P (w)
&& !WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
{
int x0, x1, y0, y1;
window_box_edges (w, -1, &x0, &y0, &x1, &y1);
y1 -= 1;
if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
x0 -= 1;
rif->draw_vertical_window_border (w, x0, y0, y1);
}
}
static int
expose_window (w, fr)
struct window *w;
XRectangle *fr;
{
struct frame *f = XFRAME (w->frame);
XRectangle wr, r;
int mouse_face_overwritten_p = 0;
if (w->current_matrix == NULL)
return 0;
if (w == updated_window)
{
SET_FRAME_GARBAGED (f);
return 0;
}
wr.x = WINDOW_LEFT_EDGE_X (w);
wr.y = WINDOW_TOP_EDGE_Y (w);
wr.width = WINDOW_TOTAL_WIDTH (w);
wr.height = WINDOW_TOTAL_HEIGHT (w);
if (x_intersect_rectangles (fr, &wr, &r))
{
int yb = window_text_bottom_y (w);
struct glyph_row *row;
int cursor_cleared_p;
struct glyph_row *first_overlapping_row, *last_overlapping_row;
TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
r.x, r.y, r.width, r.height));
r.x -= WINDOW_LEFT_EDGE_X (w);
r.y -= WINDOW_TOP_EDGE_Y (w);
if (!w->pseudo_window_p
&& phys_cursor_in_rect_p (w, &r))
{
x_clear_cursor (w);
cursor_cleared_p = 1;
}
else
cursor_cleared_p = 0;
first_overlapping_row = last_overlapping_row = NULL;
for (row = w->current_matrix->rows;
row->enabled_p;
++row)
{
int y0 = row->y;
int y1 = MATRIX_ROW_BOTTOM_Y (row);
if ((y0 >= r.y && y0 < r.y + r.height)
|| (y1 > r.y && y1 < r.y + r.height)
|| (r.y >= y0 && r.y < y1)
|| (r.y + r.height > y0 && r.y + r.height < y1))
{
if (row->overlapping_p && !row->mode_line_p)
{
if (first_overlapping_row == NULL)
first_overlapping_row = row;
last_overlapping_row = row;
}
if (expose_line (w, row, &r))
mouse_face_overwritten_p = 1;
}
if (y1 >= yb)
break;
}
if (WINDOW_WANTS_MODELINE_P (w)
&& (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
row->enabled_p)
&& row->y < r.y + r.height)
{
if (expose_line (w, row, &r))
mouse_face_overwritten_p = 1;
}
if (!w->pseudo_window_p)
{
if (first_overlapping_row)
expose_overlaps (w, first_overlapping_row, last_overlapping_row);
x_draw_vertical_border (w);
if (cursor_cleared_p)
update_window_cursor (w, 1);
}
}
return mouse_face_overwritten_p;
}
static int
expose_window_tree (w, r)
struct window *w;
XRectangle *r;
{
struct frame *f = XFRAME (w->frame);
int mouse_face_overwritten_p = 0;
while (w && !FRAME_GARBAGED_P (f))
{
if (!NILP (w->hchild))
mouse_face_overwritten_p
|= expose_window_tree (XWINDOW (w->hchild), r);
else if (!NILP (w->vchild))
mouse_face_overwritten_p
|= expose_window_tree (XWINDOW (w->vchild), r);
else
mouse_face_overwritten_p |= expose_window (w, r);
w = NILP (w->next) ? NULL : XWINDOW (w->next);
}
return mouse_face_overwritten_p;
}
void
expose_frame (f, x, y, w, h)
struct frame *f;
int x, y, w, h;
{
XRectangle r;
int mouse_face_overwritten_p = 0;
TRACE ((stderr, "expose_frame "));
if (FRAME_GARBAGED_P (f))
{
TRACE ((stderr, " garbaged\n"));
return;
}
if (FRAME_FACE_CACHE (f) == NULL
|| FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
{
TRACE ((stderr, " no faces\n"));
return;
}
if (w == 0 || h == 0)
{
r.x = r.y = 0;
r.width = FRAME_COLUMN_WIDTH (f) * FRAME_COLS (f);
r.height = FRAME_LINE_HEIGHT (f) * FRAME_LINES (f);
}
else
{
r.x = x;
r.y = y;
r.width = w;
r.height = h;
}
TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
if (WINDOWP (f->tool_bar_window))
mouse_face_overwritten_p
|= expose_window (XWINDOW (f->tool_bar_window), &r);
#ifdef HAVE_X_WINDOWS
#ifndef MSDOS
#ifndef USE_X_TOOLKIT
if (WINDOWP (f->menu_bar_window))
mouse_face_overwritten_p
|= expose_window (XWINDOW (f->menu_bar_window), &r);
#endif
#endif
#endif
if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
if (f == dpyinfo->mouse_face_mouse_frame)
{
int x = dpyinfo->mouse_face_mouse_x;
int y = dpyinfo->mouse_face_mouse_y;
clear_mouse_face (dpyinfo);
note_mouse_highlight (f, x, y);
}
}
}
int
x_intersect_rectangles (r1, r2, result)
XRectangle *r1, *r2, *result;
{
XRectangle *left, *right;
XRectangle *upper, *lower;
int intersection_p = 0;
if (r1->x < r2->x)
left = r1, right = r2;
else
left = r2, right = r1;
if (right->x <= left->x + left->width)
{
result->x = right->x;
result->width = (min (left->x + left->width, right->x + right->width)
- result->x);
if (r1->y < r2->y)
upper = r1, lower = r2;
else
upper = r2, lower = r1;
if (lower->y <= upper->y + upper->height)
{
result->y = lower->y;
result->height = (min (lower->y + lower->height,
upper->y + upper->height)
- result->y);
intersection_p = 1;
}
}
return intersection_p;
}
#endif
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);
message_dolog_marker1 = Fmake_marker ();
staticpro (&message_dolog_marker1);
message_dolog_marker2 = Fmake_marker ();
staticpro (&message_dolog_marker2);
message_dolog_marker3 = Fmake_marker ();
staticpro (&message_dolog_marker3);
#if GLYPH_DEBUG
defsubr (&Sdump_frame_glyph_matrix);
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);
defsubr (&Slookup_image_map);
#endif
defsubr (&Sformat_mode_line);
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);
Qslice = intern ("slice");
staticpro (&Qslice);
Qspace = intern ("space");
staticpro (&Qspace);
Qmargin = intern ("margin");
staticpro (&Qmargin);
Qpointer = intern ("pointer");
staticpro (&Qpointer);
Qleft_margin = intern ("left-margin");
staticpro (&Qleft_margin);
Qright_margin = intern ("right-margin");
staticpro (&Qright_margin);
Qcenter = intern ("center");
staticpro (&Qcenter);
Qline_height = intern ("line-height");
staticpro (&Qline_height);
QCalign_to = intern (":align-to");
staticpro (&QCalign_to);
QCrelative_width = intern (":relative-width");
staticpro (&QCrelative_width);
QCrelative_height = intern (":relative-height");
staticpro (&QCrelative_height);
QCeval = intern (":eval");
staticpro (&QCeval);
QCpropertize = intern (":propertize");
staticpro (&QCpropertize);
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);
Qescape_glyph = intern ("escape-glyph");
staticpro (&Qescape_glyph);
Qnobreak_space = intern ("nobreak-space");
staticpro (&Qnobreak_space);
Qimage = intern ("image");
staticpro (&Qimage);
QCmap = intern (":map");
staticpro (&QCmap);
QCpointer = intern (":pointer");
staticpro (&QCpointer);
Qrect = intern ("rect");
staticpro (&Qrect);
Qcircle = intern ("circle");
staticpro (&Qcircle);
Qpoly = intern ("poly");
staticpro (&Qpoly);
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);
Qbar = intern ("bar");
staticpro (&Qbar);
Qhbar = intern ("hbar");
staticpro (&Qhbar);
Qbox = intern ("box");
staticpro (&Qbox);
Qhollow = intern ("hollow");
staticpro (&Qhollow);
Qhand = intern ("hand");
staticpro (&Qhand);
Qarrow = intern ("arrow");
staticpro (&Qarrow);
Qtext = intern ("text");
staticpro (&Qtext);
Qrisky_local_variable = intern ("risky-local-variable");
staticpro (&Qrisky_local_variable);
Qinhibit_free_realized_faces = intern ("inhibit-free-realized-faces");
staticpro (&Qinhibit_free_realized_faces);
list_of_error = Fcons (Fcons (intern ("error"),
Fcons (intern ("void-variable"), Qnil)),
Qnil);
staticpro (&list_of_error);
Qlast_arrow_position = intern ("last-arrow-position");
staticpro (&Qlast_arrow_position);
Qlast_arrow_string = intern ("last-arrow-string");
staticpro (&Qlast_arrow_string);
Qoverlay_arrow_string = intern ("overlay-arrow-string");
staticpro (&Qoverlay_arrow_string);
Qoverlay_arrow_bitmap = intern ("overlay-arrow-bitmap");
staticpro (&Qoverlay_arrow_bitmap);
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);
mode_line_proptrans_alist = Qnil;
staticpro (&mode_line_proptrans_alist);
mode_line_string_list = Qnil;
staticpro (&mode_line_string_list);
mode_line_string_face = Qnil;
staticpro (&mode_line_string_face);
mode_line_string_face_prop = Qnil;
staticpro (&mode_line_string_face_prop);
Vmode_line_unwind_vector = Qnil;
staticpro (&Vmode_line_unwind_vector);
help_echo_string = Qnil;
staticpro (&help_echo_string);
help_echo_object = Qnil;
staticpro (&help_echo_object);
help_echo_window = Qnil;
staticpro (&help_echo_window);
previous_help_echo_string = Qnil;
staticpro (&previous_help_echo_string);
help_echo_pos = -1;
#ifdef HAVE_WINDOW_SYSTEM
DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
doc: );
x_stretch_cursor_p = 0;
#endif
DEFVAR_LISP ("show-trailing-whitespace", &Vshow_trailing_whitespace,
doc: );
Vshow_trailing_whitespace = Qnil;
DEFVAR_LISP ("nobreak-char-display", &Vnobreak_char_display,
doc: );
Vnobreak_char_display = Qt;
DEFVAR_LISP ("void-text-area-pointer", &Vvoid_text_area_pointer,
doc: );
Vvoid_text_area_pointer = Qarrow;
DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay,
doc: );
Vinhibit_redisplay = Qnil;
DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
doc: );
Vglobal_mode_string = Qnil;
DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
doc: );
Voverlay_arrow_position = Qnil;
DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
doc: );
Voverlay_arrow_string = build_string ("=>");
DEFVAR_LISP ("overlay-arrow-variable-list", &Voverlay_arrow_variable_list,
doc: );
Voverlay_arrow_variable_list
= Fcons (intern ("overlay-arrow-position"), Qnil);
DEFVAR_INT ("scroll-step", &scroll_step,
doc: );
DEFVAR_INT ("scroll-conservatively", &scroll_conservatively,
doc: );
scroll_conservatively = 0;
DEFVAR_INT ("scroll-margin", &scroll_margin,
doc: );
scroll_margin = 0;
DEFVAR_LISP ("display-pixels-per-inch", &Vdisplay_pixels_per_inch,
doc: );
Vdisplay_pixels_per_inch = make_float (72.0);
#if GLYPH_DEBUG
DEFVAR_INT ("debug-end-pos", &debug_end_pos, doc: );
#endif
DEFVAR_BOOL ("truncate-partial-width-windows",
&truncate_partial_width_windows,
doc: );
truncate_partial_width_windows = 1;
DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
doc: );
mode_line_inverse_video = 1;
DEFVAR_LISP ("line-number-display-limit", &Vline_number_display_limit,
doc: );
Vline_number_display_limit = Qnil;
DEFVAR_INT ("line-number-display-limit-width",
&line_number_display_limit_width,
doc: );
line_number_display_limit_width = 200;
DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
doc: );
highlight_nonselected_windows = 0;
DEFVAR_BOOL ("multiple-frames", &multiple_frames,
doc: );
DEFVAR_LISP ("frame-title-format", &Vframe_title_format,
doc: );
DEFVAR_LISP ("icon-title-format", &Vicon_title_format,
doc: );
Vicon_title_format
= Vframe_title_format
= Fcons (intern ("multiple-frames"),
Fcons (build_string ("%b"),
Fcons (Fcons (empty_string,
Fcons (intern ("invocation-name"),
Fcons (build_string ("@"),
Fcons (intern ("system-name"),
Qnil)))),
Qnil)));
DEFVAR_LISP ("message-log-max", &Vmessage_log_max,
doc: );
Vmessage_log_max = make_number (100);
DEFVAR_LISP ("window-size-change-functions", &Vwindow_size_change_functions,
doc: );
Vwindow_size_change_functions = Qnil;
DEFVAR_LISP ("window-scroll-functions", &Vwindow_scroll_functions,
doc: );
Vwindow_scroll_functions = Qnil;
DEFVAR_LISP ("redisplay-end-trigger-functions", &Vredisplay_end_trigger_functions,
doc: );
Vredisplay_end_trigger_functions = Qnil;
DEFVAR_LISP ("mouse-autoselect-window", &Vmouse_autoselect_window,
doc: );
Vmouse_autoselect_window = Qnil;
DEFVAR_LISP ("auto-resize-tool-bars", &Vauto_resize_tool_bars,
doc: );
Vauto_resize_tool_bars = Qt;
DEFVAR_BOOL ("auto-raise-tool-bar-buttons", &auto_raise_tool_bar_buttons_p,
doc: );
auto_raise_tool_bar_buttons_p = 1;
DEFVAR_BOOL ("make-cursor-line-fully-visible", &make_cursor_line_fully_visible_p,
doc: );
make_cursor_line_fully_visible_p = 1;
DEFVAR_LISP ("tool-bar-border", &Vtool_bar_border,
doc: );
Vtool_bar_border = Qinternal_border_width;
DEFVAR_LISP ("tool-bar-button-margin", &Vtool_bar_button_margin,
doc: );
Vtool_bar_button_margin = make_number (DEFAULT_TOOL_BAR_BUTTON_MARGIN);
DEFVAR_INT ("tool-bar-button-relief", &tool_bar_button_relief,
doc: );
tool_bar_button_relief = DEFAULT_TOOL_BAR_BUTTON_RELIEF;
DEFVAR_LISP ("fontification-functions", &Vfontification_functions,
doc: );
Vfontification_functions = Qnil;
Fmake_variable_buffer_local (Qfontification_functions);
DEFVAR_BOOL ("unibyte-display-via-language-environment",
&unibyte_display_via_language_environment,
doc: );
unibyte_display_via_language_environment = 0;
DEFVAR_LISP ("max-mini-window-height", &Vmax_mini_window_height,
doc: );
Vmax_mini_window_height = make_float (0.25);
DEFVAR_LISP ("resize-mini-windows", &Vresize_mini_windows,
doc: );
Vresize_mini_windows = Qgrow_only;
DEFVAR_LISP ("blink-cursor-alist", &Vblink_cursor_alist,
doc: );
Vblink_cursor_alist = Qnil;
DEFVAR_BOOL ("auto-hscroll-mode", &automatic_hscrolling_p,
doc: );
automatic_hscrolling_p = 1;
DEFVAR_INT ("hscroll-margin", &hscroll_margin,
doc: );
hscroll_margin = 5;
DEFVAR_LISP ("hscroll-step", &Vhscroll_step,
doc: );
Vhscroll_step = make_number (0);
DEFVAR_BOOL ("message-truncate-lines", &message_truncate_lines,
doc: );
message_truncate_lines = 0;
DEFVAR_LISP ("menu-bar-update-hook", &Vmenu_bar_update_hook,
doc: );
Vmenu_bar_update_hook = Qnil;
DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame,
doc: );
Vmenu_updating_frame = Qnil;
DEFVAR_BOOL ("inhibit-menubar-update", &inhibit_menubar_update,
doc: );
inhibit_menubar_update = 0;
DEFVAR_BOOL ("inhibit-eval-during-redisplay", &inhibit_eval_during_redisplay,
doc: );
inhibit_eval_during_redisplay = 0;
DEFVAR_BOOL ("inhibit-free-realized-faces", &inhibit_free_realized_faces,
doc: );
inhibit_free_realized_faces = 0;
#if GLYPH_DEBUG
DEFVAR_BOOL ("inhibit-try-window-id", &inhibit_try_window_id,
doc: );
inhibit_try_window_id = 0;
DEFVAR_BOOL ("inhibit-try-window-reusing", &inhibit_try_window_reusing,
doc: );
inhibit_try_window_reusing = 0;
DEFVAR_BOOL ("inhibit-try-cursor-movement", &inhibit_try_cursor_movement,
doc: );
inhibit_try_cursor_movement = 0;
#endif
DEFVAR_INT ("overline-margin", &overline_margin,
doc: );
overline_margin = 2;
}
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_line = make_number (FRAME_TOP_MARGIN (f));
set_window_height (root_window,
FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f),
0);
mini_w->top_line = make_number (FRAME_LINES (f) - 1);
set_window_height (minibuf_window, 1, 0);
XWINDOW (root_window)->total_cols = make_number (FRAME_COLS (f));
mini_w->total_cols = make_number (FRAME_COLS (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 ('.');
}
{
int size = 100;
mode_line_noprop_buf = (char *) xmalloc (size);
mode_line_noprop_buf_end = mode_line_noprop_buf + size;
mode_line_noprop_ptr = mode_line_noprop_buf;
mode_line_target = MODE_LINE_DISPLAY;
}
help_echo_showing_p = 0;
}