#include <config.h>
#include <signal.h>
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "lisp.h"
#include "termchar.h"
#include "termopts.h"
#include "termhooks.h"
#include "dispextern.h"
#include "cm.h"
#include "buffer.h"
#include "charset.h"
#include "keyboard.h"
#include "frame.h"
#include "window.h"
#include "commands.h"
#include "disptab.h"
#include "indent.h"
#include "intervals.h"
#include "blockinput.h"
#include "process.h"
#include "syssignal.h"
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
#ifdef HAVE_NTGUI
#include "w32term.h"
#endif
#ifdef MAC_OS
#include "macterm.h"
#endif
#include "systime.h"
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef __GNU_LIBRARY__
#ifdef GNU_LIBRARY_PENDING_OUTPUT_COUNT
#define PENDING_OUTPUT_COUNT GNU_LIBRARY_PENDING_OUTPUT_COUNT
#else
#undef PENDING_OUTPUT_COUNT
#define PENDING_OUTPUT_COUNT(FILE) ((FILE)->__bufp - (FILE)->__buffer)
#endif
#else
#if !defined (PENDING_OUTPUT_COUNT) && HAVE_STDIO_EXT_H && HAVE___FPENDING
#include <stdio_ext.h>
#define PENDING_OUTPUT_COUNT(FILE) __fpending (FILE)
#endif
#ifndef PENDING_OUTPUT_COUNT
#define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_ptr - (FILE)->_base)
#endif
#endif
#if defined(HAVE_TERM_H) && defined (GNU_LINUX) && defined (HAVE_LIBNCURSES)
#include <term.h>
#endif
struct dim
{
int width;
int height;
};
static struct glyph_matrix *save_current_matrix P_ ((struct frame *));
static void restore_current_matrix P_ ((struct frame *, struct glyph_matrix *));
static int showing_window_margins_p P_ ((struct window *));
static void fake_current_matrices P_ ((Lisp_Object));
static void redraw_overlapping_rows P_ ((struct window *, int));
static void redraw_overlapped_rows P_ ((struct window *, int));
static int count_blanks P_ ((struct glyph *, int));
static int count_match P_ ((struct glyph *, struct glyph *,
struct glyph *, struct glyph *));
static unsigned line_draw_cost P_ ((struct glyph_matrix *, int));
static void update_frame_line P_ ((struct frame *, int));
static struct dim allocate_matrices_for_frame_redisplay
P_ ((Lisp_Object, int, int, int, int *));
static void allocate_matrices_for_window_redisplay P_ ((struct window *));
static int realloc_glyph_pool P_ ((struct glyph_pool *, struct dim));
static void adjust_frame_glyphs P_ ((struct frame *));
struct glyph_matrix *new_glyph_matrix P_ ((struct glyph_pool *));
static void free_glyph_matrix P_ ((struct glyph_matrix *));
static void adjust_glyph_matrix P_ ((struct window *, struct glyph_matrix *,
int, int, struct dim));
static void change_frame_size_1 P_ ((struct frame *, int, int, int, int, int));
static void swap_glyph_pointers P_ ((struct glyph_row *, struct glyph_row *));
#if GLYPH_DEBUG
static int glyph_row_slice_p P_ ((struct glyph_row *, struct glyph_row *));
#endif
static void fill_up_frame_row_with_spaces P_ ((struct glyph_row *, int));
static void build_frame_matrix_from_window_tree P_ ((struct glyph_matrix *,
struct window *));
static void build_frame_matrix_from_leaf_window P_ ((struct glyph_matrix *,
struct window *));
static struct glyph_pool *new_glyph_pool P_ ((void));
static void free_glyph_pool P_ ((struct glyph_pool *));
static void adjust_frame_glyphs_initially P_ ((void));
static void adjust_frame_message_buffer P_ ((struct frame *));
static void adjust_decode_mode_spec_buffer P_ ((struct frame *));
static void fill_up_glyph_row_with_spaces P_ ((struct glyph_row *));
static void build_frame_matrix P_ ((struct frame *));
void clear_current_matrices P_ ((struct frame *));
void scroll_glyph_matrix_range P_ ((struct glyph_matrix *, int, int,
int, int));
static void clear_window_matrices P_ ((struct window *, int));
static void fill_up_glyph_row_area_with_spaces P_ ((struct glyph_row *, int));
static int scrolling_window P_ ((struct window *, int));
static int update_window_line P_ ((struct window *, int, int *));
static void update_marginal_area P_ ((struct window *, int, int));
static int update_text_area P_ ((struct window *, int));
static void make_current P_ ((struct glyph_matrix *, struct glyph_matrix *,
int));
static void mirror_make_current P_ ((struct window *, int));
void check_window_matrix_pointers P_ ((struct window *));
#if GLYPH_DEBUG
static void check_matrix_pointers P_ ((struct glyph_matrix *,
struct glyph_matrix *));
#endif
static void mirror_line_dance P_ ((struct window *, int, int, int *, char *));
static int update_window_tree P_ ((struct window *, int));
static int update_window P_ ((struct window *, int));
static int update_frame_1 P_ ((struct frame *, int, int));
static void set_window_cursor_after_update P_ ((struct window *));
static int row_equal_p P_ ((struct window *, struct glyph_row *,
struct glyph_row *, int));
static void adjust_frame_glyphs_for_window_redisplay P_ ((struct frame *));
static void adjust_frame_glyphs_for_frame_redisplay P_ ((struct frame *));
static void reverse_rows P_ ((struct glyph_matrix *, int, int));
static int margin_glyphs_to_reserve P_ ((struct window *, int, Lisp_Object));
static void sync_window_with_frame_matrix_rows P_ ((struct window *));
struct window *frame_row_to_window P_ ((struct window *, int));
int redisplay_dont_pause;
#ifdef EMACS_HAS_USECS
#define PERIODIC_PREEMPTION_CHECKING 1
#else
#define PERIODIC_PREEMPTION_CHECKING 0
#endif
#if PERIODIC_PREEMPTION_CHECKING
Lisp_Object Vredisplay_preemption_period;
static EMACS_TIME preemption_period;
static EMACS_TIME preemption_next_check;
#endif
int frame_garbaged;
int display_completed;
int visible_bell;
int inverse_video;
EMACS_INT baud_rate;
Lisp_Object Vwindow_system;
Lisp_Object Vwindow_system_version;
Lisp_Object Vglyph_table;
Lisp_Object Vstandard_display_table;
int cursor_in_echo_area;
Lisp_Object Qdisplay_table, Qredisplay_dont_pause;
Lisp_Object selected_frame;
struct frame *last_nonminibuf_frame;
FILE *termscript;
struct cm Wcm;
int delayed_size_change;
static int glyphs_initialized_initially_p;
struct window *updated_window;
struct glyph_row *updated_row;
int updated_area;
struct glyph space_glyph;
int redisplay_performed_directly_p;
int glyph_matrix_count;
int glyph_pool_count;
static struct frame *frame_matrix_frame;
struct redisplay_interface *rif;
int fonts_changed_p;
#if GLYPH_DEBUG
static int window_to_frame_vpos P_ ((struct window *, int));
static int window_to_frame_hpos P_ ((struct window *, int));
#define WINDOW_TO_FRAME_VPOS(W, VPOS) window_to_frame_vpos ((W), (VPOS))
#define WINDOW_TO_FRAME_HPOS(W, HPOS) window_to_frame_hpos ((W), (HPOS))
struct redisplay_history
{
char trace[512 + 100];
};
#define REDISPLAY_HISTORY_SIZE 30
static struct redisplay_history redisplay_history[REDISPLAY_HISTORY_SIZE];
static int history_idx;
static unsigned history_tick;
static void add_frame_display_history P_ ((struct frame *, int));
static void add_window_display_history P_ ((struct window *, char *, int));
static void
add_window_display_history (w, msg, paused_p)
struct window *w;
char *msg;
int paused_p;
{
char *buf;
if (history_idx >= REDISPLAY_HISTORY_SIZE)
history_idx = 0;
buf = redisplay_history[history_idx].trace;
++history_idx;
sprintf (buf, "%d: window %p (`%s')%s\n",
history_tick++,
w,
((BUFFERP (w->buffer)
&& STRINGP (XBUFFER (w->buffer)->name))
? (char *) SDATA (XBUFFER (w->buffer)->name)
: "???"),
paused_p ? " ***paused***" : "");
strcat (buf, msg);
}
static void
add_frame_display_history (f, paused_p)
struct frame *f;
int paused_p;
{
char *buf;
if (history_idx >= REDISPLAY_HISTORY_SIZE)
history_idx = 0;
buf = redisplay_history[history_idx].trace;
++history_idx;
sprintf (buf, "%d: update frame %p%s",
history_tick++,
f, paused_p ? " ***paused***" : "");
}
DEFUN ("dump-redisplay-history", Fdump_redisplay_history,
Sdump_redisplay_history, 0, 0, "",
doc: )
()
{
int i;
for (i = history_idx - 1; i != history_idx; --i)
{
if (i < 0)
i = REDISPLAY_HISTORY_SIZE - 1;
fprintf (stderr, "%s\n", redisplay_history[i].trace);
}
return Qnil;
}
#else
#define WINDOW_TO_FRAME_VPOS(W, VPOS) ((VPOS) + WINDOW_TOP_EDGE_LINE (W))
#define WINDOW_TO_FRAME_HPOS(W, HPOS) ((HPOS) + WINDOW_LEFT_EDGE_COL (W))
#endif
void
safe_bcopy (from, to, size)
const char *from;
char *to;
int size;
{
if (size <= 0 || from == to)
return;
if (to < from || from + size <= to)
bcopy (from, to, size);
else
{
register const char *endf = from + size;
register char *endt = to + size;
if (to - from < 64)
{
do
*--endt = *--endf;
while (endf != from);
}
else
{
for (;;)
{
endt -= (to - from);
endf -= (to - from);
if (endt < to)
break;
bcopy (endf, endt, to - from);
}
bcopy (from, to, endt - from);
}
}
}
struct glyph_matrix *
new_glyph_matrix (pool)
struct glyph_pool *pool;
{
struct glyph_matrix *result;
result = (struct glyph_matrix *) xmalloc (sizeof *result);
bzero (result, sizeof *result);
++glyph_matrix_count;
result->pool = pool;
return result;
}
static void
free_glyph_matrix (matrix)
struct glyph_matrix *matrix;
{
if (matrix)
{
int i;
if (--glyph_matrix_count < 0)
abort ();
if (matrix->pool == NULL)
for (i = 0; i < matrix->rows_allocated; ++i)
xfree (matrix->rows[i].glyphs[LEFT_MARGIN_AREA]);
xfree (matrix->rows);
xfree (matrix);
}
}
static int
margin_glyphs_to_reserve (w, total_glyphs, margin)
struct window *w;
int total_glyphs;
Lisp_Object margin;
{
int n;
if (NUMBERP (margin))
{
int width = XFASTINT (w->total_cols);
double d = max (0, XFLOATINT (margin));
d = min (width / 2 - 1, d);
n = (int) ((double) total_glyphs / width * d);
}
else
n = 0;
return n;
}
static void
adjust_glyph_matrix (w, matrix, x, y, dim)
struct window *w;
struct glyph_matrix *matrix;
int x, y;
struct dim dim;
{
int i;
int new_rows;
int marginal_areas_changed_p = 0;
int header_line_changed_p = 0;
int header_line_p = 0;
int left = -1, right = -1;
int window_width = -1, window_height;
if (w)
{
window_box (w, -1, 0, 0, &window_width, &window_height);
header_line_p = WINDOW_WANTS_HEADER_LINE_P (w);
header_line_changed_p = header_line_p != matrix->header_line_p;
}
matrix->header_line_p = header_line_p;
if (matrix->pool == NULL)
{
left = margin_glyphs_to_reserve (w, dim.width, w->left_margin_cols);
right = margin_glyphs_to_reserve (w, dim.width, w->right_margin_cols);
xassert (left >= 0 && right >= 0);
marginal_areas_changed_p = (left != matrix->left_margin_glyphs
|| right != matrix->right_margin_glyphs);
if (!marginal_areas_changed_p
&& !fonts_changed_p
&& !header_line_changed_p
&& matrix->window_left_col == WINDOW_LEFT_EDGE_COL (w)
&& matrix->window_top_line == WINDOW_TOP_EDGE_LINE (w)
&& matrix->window_height == window_height
&& matrix->window_vscroll == w->vscroll
&& matrix->window_width == window_width)
return;
}
if (matrix->rows_allocated < dim.height)
{
int size = dim.height * sizeof (struct glyph_row);
new_rows = dim.height - matrix->rows_allocated;
matrix->rows = (struct glyph_row *) xrealloc (matrix->rows, size);
bzero (matrix->rows + matrix->rows_allocated,
new_rows * sizeof *matrix->rows);
matrix->rows_allocated = dim.height;
}
else
new_rows = 0;
if (matrix->pool)
{
xassert (matrix->pool->glyphs);
if (w)
{
left = margin_glyphs_to_reserve (w, dim.width,
w->left_margin_cols);
right = margin_glyphs_to_reserve (w, dim.width,
w->right_margin_cols);
}
else
left = right = 0;
for (i = 0; i < dim.height; ++i)
{
struct glyph_row *row = &matrix->rows[i];
row->glyphs[LEFT_MARGIN_AREA]
= (matrix->pool->glyphs
+ (y + i) * matrix->pool->ncolumns
+ x);
if (w == NULL
|| row == matrix->rows + dim.height - 1
|| (row == matrix->rows && matrix->header_line_p))
{
row->glyphs[TEXT_AREA]
= row->glyphs[LEFT_MARGIN_AREA];
row->glyphs[RIGHT_MARGIN_AREA]
= row->glyphs[TEXT_AREA] + dim.width;
row->glyphs[LAST_AREA]
= row->glyphs[RIGHT_MARGIN_AREA];
}
else
{
row->glyphs[TEXT_AREA]
= row->glyphs[LEFT_MARGIN_AREA] + left;
row->glyphs[RIGHT_MARGIN_AREA]
= row->glyphs[TEXT_AREA] + dim.width - left - right;
row->glyphs[LAST_AREA]
= row->glyphs[LEFT_MARGIN_AREA] + dim.width;
}
}
matrix->left_margin_glyphs = left;
matrix->right_margin_glyphs = right;
}
else
{
if (dim.width > matrix->matrix_w
|| new_rows
|| header_line_changed_p
|| marginal_areas_changed_p)
{
struct glyph_row *row = matrix->rows;
struct glyph_row *end = row + matrix->rows_allocated;
while (row < end)
{
row->glyphs[LEFT_MARGIN_AREA]
= (struct glyph *) xrealloc (row->glyphs[LEFT_MARGIN_AREA],
(dim.width
* sizeof (struct glyph)));
if (row == matrix->rows + dim.height - 1
|| (row == matrix->rows && matrix->header_line_p))
{
row->glyphs[TEXT_AREA]
= row->glyphs[LEFT_MARGIN_AREA];
row->glyphs[RIGHT_MARGIN_AREA]
= row->glyphs[TEXT_AREA] + dim.width;
row->glyphs[LAST_AREA]
= row->glyphs[RIGHT_MARGIN_AREA];
}
else
{
row->glyphs[TEXT_AREA]
= row->glyphs[LEFT_MARGIN_AREA] + left;
row->glyphs[RIGHT_MARGIN_AREA]
= row->glyphs[TEXT_AREA] + dim.width - left - right;
row->glyphs[LAST_AREA]
= row->glyphs[LEFT_MARGIN_AREA] + dim.width;
}
++row;
}
}
xassert (left >= 0 && right >= 0);
matrix->left_margin_glyphs = left;
matrix->right_margin_glyphs = right;
}
matrix->nrows = dim.height;
xassert (matrix->nrows >= 0);
if (w)
{
if (matrix == w->current_matrix)
{
if (window_width < 0)
window_width = window_box_width (w, -1);
if (!marginal_areas_changed_p
&& !header_line_changed_p
&& new_rows == 0
&& dim.width == matrix->matrix_w
&& matrix->window_left_col == WINDOW_LEFT_EDGE_COL (w)
&& matrix->window_top_line == WINDOW_TOP_EDGE_LINE (w)
&& matrix->window_width == window_width)
{
for (i = 0; i < matrix->nrows && matrix->rows[i].enabled_p; ++i)
if (MATRIX_ROW_BOTTOM_Y (matrix->rows + i) >= window_height)
{
++i;
break;
}
if (INTEGERP (w->window_end_vpos)
&& XFASTINT (w->window_end_vpos) >= i)
w->window_end_valid = Qnil;
while (i < matrix->nrows)
matrix->rows[i++].enabled_p = 0;
}
else
{
for (i = 0; i < matrix->nrows; ++i)
matrix->rows[i].enabled_p = 0;
}
}
else if (matrix == w->desired_matrix)
{
for (i = 0; i < matrix->nrows; ++i)
matrix->rows[i].enabled_p = 0;
}
}
matrix->matrix_x = x;
matrix->matrix_y = y;
matrix->matrix_w = dim.width;
matrix->matrix_h = dim.height;
if (w)
{
matrix->window_left_col = WINDOW_LEFT_EDGE_COL (w);
matrix->window_top_line = WINDOW_TOP_EDGE_LINE (w);
matrix->window_height = window_height;
matrix->window_width = window_width;
matrix->window_vscroll = w->vscroll;
}
}
static void
reverse_rows (matrix, start, end)
struct glyph_matrix *matrix;
int start, end;
{
int i, j;
for (i = start, j = end - 1; i < j; ++i, --j)
{
struct glyph_row temp;
temp = matrix->rows[i];
matrix->rows[i] = matrix->rows[j];
matrix->rows[j] = temp;
}
}
void
rotate_matrix (matrix, first, last, by)
struct glyph_matrix *matrix;
int first, last, by;
{
if (by < 0)
{
by = -by;
reverse_rows (matrix, first, first + by);
reverse_rows (matrix, first + by, last);
reverse_rows (matrix, first, last);
}
else if (by > 0)
{
reverse_rows (matrix, last - by, last);
reverse_rows (matrix, first, last - by);
reverse_rows (matrix, first, last);
}
}
void
increment_matrix_positions (matrix, start, end, delta, delta_bytes)
struct glyph_matrix *matrix;
int start, end, delta, delta_bytes;
{
xassert (start >= 0 && start <= matrix->nrows);
xassert (end >= 0 && end <= matrix->nrows);
xassert (start <= end);
for (; start < end; ++start)
increment_row_positions (matrix->rows + start, delta, delta_bytes);
}
void
enable_glyph_matrix_rows (matrix, start, end, enabled_p)
struct glyph_matrix *matrix;
int start, end;
int enabled_p;
{
xassert (start <= end);
xassert (start >= 0 && start < matrix->nrows);
xassert (end >= 0 && end <= matrix->nrows);
for (; start < end; ++start)
matrix->rows[start].enabled_p = enabled_p != 0;
}
void
clear_glyph_matrix (matrix)
struct glyph_matrix *matrix;
{
if (matrix)
{
enable_glyph_matrix_rows (matrix, 0, matrix->nrows, 0);
matrix->no_scrolling_p = 0;
}
}
void
shift_glyph_matrix (w, matrix, start, end, dy)
struct window *w;
struct glyph_matrix *matrix;
int start, end, dy;
{
int min_y, max_y;
xassert (start <= end);
xassert (start >= 0 && start < matrix->nrows);
xassert (end >= 0 && end <= matrix->nrows);
min_y = WINDOW_HEADER_LINE_HEIGHT (w);
max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (w);
for (; start < end; ++start)
{
struct glyph_row *row = &matrix->rows[start];
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;
}
}
void
clear_current_matrices (f)
register struct frame *f;
{
if (f->current_matrix)
clear_glyph_matrix (f->current_matrix);
if (WINDOWP (f->menu_bar_window))
clear_glyph_matrix (XWINDOW (f->menu_bar_window)->current_matrix);
if (WINDOWP (f->tool_bar_window))
clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
xassert (WINDOWP (FRAME_ROOT_WINDOW (f)));
clear_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)), 0);
}
void
clear_desired_matrices (f)
register struct frame *f;
{
if (f->desired_matrix)
clear_glyph_matrix (f->desired_matrix);
if (WINDOWP (f->menu_bar_window))
clear_glyph_matrix (XWINDOW (f->menu_bar_window)->desired_matrix);
if (WINDOWP (f->tool_bar_window))
clear_glyph_matrix (XWINDOW (f->tool_bar_window)->desired_matrix);
xassert (WINDOWP (FRAME_ROOT_WINDOW (f)));
clear_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)), 1);
}
static void
clear_window_matrices (w, desired_p)
struct window *w;
int desired_p;
{
while (w)
{
if (!NILP (w->hchild))
{
xassert (WINDOWP (w->hchild));
clear_window_matrices (XWINDOW (w->hchild), desired_p);
}
else if (!NILP (w->vchild))
{
xassert (WINDOWP (w->vchild));
clear_window_matrices (XWINDOW (w->vchild), desired_p);
}
else
{
if (desired_p)
clear_glyph_matrix (w->desired_matrix);
else
{
clear_glyph_matrix (w->current_matrix);
w->window_end_valid = Qnil;
}
}
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
}
static struct glyph_row null_row;
void
clear_glyph_row (row)
struct glyph_row *row;
{
struct glyph *p[1 + LAST_AREA];
p[LEFT_MARGIN_AREA] = row->glyphs[LEFT_MARGIN_AREA];
p[TEXT_AREA] = row->glyphs[TEXT_AREA];
p[RIGHT_MARGIN_AREA] = row->glyphs[RIGHT_MARGIN_AREA];
p[LAST_AREA] = row->glyphs[LAST_AREA];
*row = null_row;
row->glyphs[LEFT_MARGIN_AREA] = p[LEFT_MARGIN_AREA];
row->glyphs[TEXT_AREA] = p[TEXT_AREA];
row->glyphs[RIGHT_MARGIN_AREA] = p[RIGHT_MARGIN_AREA];
row->glyphs[LAST_AREA] = p[LAST_AREA];
#if 0
bzero (p[0], (char *) p[LAST_AREA] - (char *) p[0]);
#endif
}
void
blank_row (w, row, y)
struct window *w;
struct glyph_row *row;
int y;
{
int min_y, max_y;
min_y = WINDOW_HEADER_LINE_HEIGHT (w);
max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (w);
clear_glyph_row (row);
row->y = y;
row->ascent = row->phys_ascent = 0;
row->height = row->phys_height = FRAME_LINE_HEIGHT (XFRAME (w->frame));
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->enabled_p = 1;
}
void
increment_row_positions (row, delta, delta_bytes)
struct glyph_row *row;
int delta, delta_bytes;
{
int area, i;
MATRIX_ROW_START_CHARPOS (row) += delta;
MATRIX_ROW_START_BYTEPOS (row) += delta_bytes;
MATRIX_ROW_END_CHARPOS (row) += delta;
MATRIX_ROW_END_BYTEPOS (row) += delta_bytes;
if (!row->enabled_p)
return;
for (area = 0; area < LAST_AREA; ++area)
for (i = 0; i < row->used[area]; ++i)
if (BUFFERP (row->glyphs[area][i].object)
&& row->glyphs[area][i].charpos > 0)
row->glyphs[area][i].charpos += delta;
if (row->used[TEXT_AREA] == 0
&& MATRIX_ROW_DISPLAYS_TEXT_P (row))
row->glyphs[TEXT_AREA]->charpos += delta;
}
#if 0
static void
swap_glyphs_in_rows (a, b)
struct glyph_row *a, *b;
{
int area;
for (area = 0; area < LAST_AREA; ++area)
{
int max_used = max (a->used[area], b->used[area]);
struct glyph *glyph_a = a->glyphs[area];
struct glyph *glyph_a_end = a->glyphs[max_used];
struct glyph *glyph_b = b->glyphs[area];
while (glyph_a < glyph_a_end)
{
struct glyph temp;
temp = *glyph_a;
*glyph_a = *glyph_b;
*glyph_b = temp;
++glyph_a;
++glyph_b;
}
}
}
#endif
static INLINE void
swap_glyph_pointers (a, b)
struct glyph_row *a, *b;
{
int i;
for (i = 0; i < LAST_AREA + 1; ++i)
{
struct glyph *temp = a->glyphs[i];
a->glyphs[i] = b->glyphs[i];
b->glyphs[i] = temp;
}
}
INLINE void
copy_row_except_pointers (to, from)
struct glyph_row *to, *from;
{
struct glyph *pointers[1 + LAST_AREA];
bcopy (to->glyphs, pointers, sizeof to->glyphs);
*to = *from;
bcopy (pointers, to->glyphs, sizeof to->glyphs);
}
void
copy_glyph_row_contents (to, from, delta, delta_bytes)
struct glyph_row *to, *from;
int delta, delta_bytes;
{
int area;
copy_row_except_pointers (to, from);
for (area = 0; area < LAST_AREA; ++area)
if (from->used[area])
bcopy (from->glyphs[area], to->glyphs[area],
from->used[area] * sizeof (struct glyph));
increment_row_positions (to, delta, delta_bytes);
}
static INLINE void
assign_row (to, from)
struct glyph_row *to, *from;
{
swap_glyph_pointers (to, from);
copy_row_except_pointers (to, from);
}
#if GLYPH_DEBUG
static int
glyph_row_slice_p (window_row, frame_row)
struct glyph_row *window_row, *frame_row;
{
struct glyph *window_glyph_start = window_row->glyphs[0];
struct glyph *frame_glyph_start = frame_row->glyphs[0];
struct glyph *frame_glyph_end = frame_row->glyphs[LAST_AREA];
return (frame_glyph_start <= window_glyph_start
&& window_glyph_start < frame_glyph_end);
}
#endif
#if 0
static struct glyph_row *
find_glyph_row_slice (window_matrix, frame_matrix, row)
struct glyph_matrix *window_matrix, *frame_matrix;
int row;
{
int i;
xassert (row >= 0 && row < frame_matrix->nrows);
for (i = 0; i < window_matrix->nrows; ++i)
if (glyph_row_slice_p (window_matrix->rows + i,
frame_matrix->rows + row))
break;
return i < window_matrix->nrows ? window_matrix->rows + i : 0;
}
#endif
void
prepare_desired_row (row)
struct glyph_row *row;
{
if (!row->enabled_p)
{
clear_glyph_row (row);
row->enabled_p = 1;
}
}
int
line_hash_code (row)
struct glyph_row *row;
{
int hash = 0;
if (row->enabled_p)
{
struct glyph *glyph = row->glyphs[TEXT_AREA];
struct glyph *end = glyph + row->used[TEXT_AREA];
while (glyph < end)
{
int c = glyph->u.ch;
int face_id = glyph->face_id;
if (must_write_spaces)
c -= SPACEGLYPH;
hash = (((hash << 4) + (hash >> 24)) & 0x0fffffff) + c;
hash = (((hash << 4) + (hash >> 24)) & 0x0fffffff) + face_id;
++glyph;
}
if (hash == 0)
hash = 1;
}
return hash;
}
static unsigned int
line_draw_cost (matrix, vpos)
struct glyph_matrix *matrix;
int vpos;
{
struct glyph_row *row = matrix->rows + vpos;
struct glyph *beg = row->glyphs[TEXT_AREA];
struct glyph *end = beg + row->used[TEXT_AREA];
int len;
Lisp_Object *glyph_table_base = GLYPH_TABLE_BASE;
int glyph_table_len = GLYPH_TABLE_LENGTH;
if (!must_write_spaces)
{
while (end > beg && CHAR_GLYPH_SPACE_P (*(end - 1)))
--end;
if (end == beg)
return 0;
while (CHAR_GLYPH_SPACE_P (*beg))
++beg;
}
if (glyph_table_base == 0)
len = end - beg;
else
{
len = 0;
while (beg < end)
{
GLYPH g = GLYPH_FROM_CHAR_GLYPH (*beg);
if (g < 0
|| GLYPH_SIMPLE_P (glyph_table_base, glyph_table_len, g))
len += 1;
else
len += GLYPH_LENGTH (glyph_table_base, g);
++beg;
}
}
return len;
}
static INLINE int
row_equal_p (w, a, b, mouse_face_p)
struct window *w;
struct glyph_row *a, *b;
int mouse_face_p;
{
if (a == b)
return 1;
else if (a->hash != b->hash)
return 0;
else
{
struct glyph *a_glyph, *b_glyph, *a_end;
int area;
if (mouse_face_p && a->mouse_face_p != b->mouse_face_p)
return 0;
for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
{
if (a->used[area] != b->used[area])
return 0;
a_glyph = a->glyphs[area];
a_end = a_glyph + a->used[area];
b_glyph = b->glyphs[area];
while (a_glyph < a_end
&& GLYPH_EQUAL_P (a_glyph, b_glyph))
++a_glyph, ++b_glyph;
if (a_glyph != a_end)
return 0;
}
if (a->fill_line_p != b->fill_line_p
|| a->cursor_in_fringe_p != b->cursor_in_fringe_p
|| a->left_fringe_bitmap != b->left_fringe_bitmap
|| a->left_fringe_face_id != b->left_fringe_face_id
|| a->right_fringe_bitmap != b->right_fringe_bitmap
|| a->right_fringe_face_id != b->right_fringe_face_id
|| a->overlay_arrow_bitmap != b->overlay_arrow_bitmap
|| a->exact_window_width_line_p != b->exact_window_width_line_p
|| a->overlapped_p != b->overlapped_p
|| (MATRIX_ROW_CONTINUATION_LINE_P (a)
!= MATRIX_ROW_CONTINUATION_LINE_P (b))
|| a->x != b->x
|| a->ascent != b->ascent
|| a->phys_ascent != b->phys_ascent
|| a->phys_height != b->phys_height
|| a->visible_height != b->visible_height)
return 0;
}
return 1;
}
static struct glyph_pool *
new_glyph_pool ()
{
struct glyph_pool *result;
result = (struct glyph_pool *) xmalloc (sizeof *result);
bzero (result, sizeof *result);
++glyph_pool_count;
return result;
}
static void
free_glyph_pool (pool)
struct glyph_pool *pool;
{
if (pool)
{
--glyph_pool_count;
xassert (glyph_pool_count >= 0);
xfree (pool->glyphs);
xfree (pool);
}
}
static int
realloc_glyph_pool (pool, matrix_dim)
struct glyph_pool *pool;
struct dim matrix_dim;
{
int needed;
int changed_p;
changed_p = (pool->glyphs == 0
|| matrix_dim.height != pool->nrows
|| matrix_dim.width != pool->ncolumns);
needed = matrix_dim.width * matrix_dim.height;
if (needed > pool->nglyphs)
{
int size = needed * sizeof (struct glyph);
if (pool->glyphs)
pool->glyphs = (struct glyph *) xrealloc (pool->glyphs, size);
else
{
pool->glyphs = (struct glyph *) xmalloc (size);
bzero (pool->glyphs, size);
}
pool->nglyphs = needed;
}
pool->nrows = matrix_dim.height;
pool->ncolumns = matrix_dim.width;
return changed_p;
}
#if GLYPH_DEBUG
void
flush_stdout ()
{
fflush (stdout);
}
void
check_matrix_pointer_lossage (matrix)
struct glyph_matrix *matrix;
{
int i, j;
for (i = 0; i < matrix->nrows; ++i)
for (j = 0; j < matrix->nrows; ++j)
xassert (i == j
|| (matrix->rows[i].glyphs[TEXT_AREA]
!= matrix->rows[j].glyphs[TEXT_AREA]));
}
struct glyph_row *
matrix_row (matrix, row)
struct glyph_matrix *matrix;
int row;
{
xassert (matrix && matrix->rows);
xassert (row >= 0 && row < matrix->nrows);
#if 0
check_matrix_pointer_lossage (matrix);
#endif
return matrix->rows + row;
}
#if 0
static void
check_matrix_invariants (w)
struct window *w;
{
struct glyph_matrix *matrix = w->current_matrix;
int yb = window_text_bottom_y (w);
struct glyph_row *row = matrix->rows;
struct glyph_row *last_text_row = NULL;
struct buffer *saved = current_buffer;
struct buffer *buffer = XBUFFER (w->buffer);
int c;
if (matrix->nrows < 2)
return;
set_buffer_temp (buffer);
while (MATRIX_ROW_DISPLAYS_TEXT_P (row)
&& MATRIX_ROW_BOTTOM_Y (row) < yb)
{
struct glyph_row *next = row + 1;
if (MATRIX_ROW_DISPLAYS_TEXT_P (row))
last_text_row = row;
xassert (MATRIX_ROW_START_BYTEPOS (row)
== CHAR_TO_BYTE (MATRIX_ROW_START_CHARPOS (row)));
if (MATRIX_ROW_END_CHARPOS (row) < BUF_ZV (current_buffer))
xassert (MATRIX_ROW_END_BYTEPOS (row)
== CHAR_TO_BYTE (MATRIX_ROW_END_CHARPOS (row)));
if (next->enabled_p && MATRIX_ROW_DISPLAYS_TEXT_P (next))
{
xassert (MATRIX_ROW_END_CHARPOS (row)
== MATRIX_ROW_START_CHARPOS (next));
xassert (MATRIX_ROW_END_BYTEPOS (row)
== MATRIX_ROW_START_BYTEPOS (next));
}
row = next;
}
xassert (w->current_matrix->nrows == w->desired_matrix->nrows);
xassert (w->desired_matrix->rows != NULL);
set_buffer_temp (saved);
}
#endif
#endif
#define NEW_LEAF_MATRIX (1 << 0)
#define CHANGED_LEAF_MATRIX (1 << 1)
static struct dim
allocate_matrices_for_frame_redisplay (window, x, y, dim_only_p,
window_change_flags)
Lisp_Object window;
int x, y;
int dim_only_p;
int *window_change_flags;
{
struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
int x0 = x, y0 = y;
int wmax = 0, hmax = 0;
struct dim total;
struct dim dim;
struct window *w;
int in_horz_combination_p;
in_horz_combination_p
= (!NILP (XWINDOW (window)->parent)
&& !NILP (XWINDOW (XWINDOW (window)->parent)->hchild));
do
{
w = XWINDOW (window);
if (!NILP (w->hchild))
dim = allocate_matrices_for_frame_redisplay (w->hchild, x, y,
dim_only_p,
window_change_flags);
else if (!NILP (w->vchild))
dim = allocate_matrices_for_frame_redisplay (w->vchild, x, y,
dim_only_p,
window_change_flags);
else
{
if (w->desired_matrix == NULL)
{
w->desired_matrix = new_glyph_matrix (f->desired_pool);
w->current_matrix = new_glyph_matrix (f->current_pool);
*window_change_flags |= NEW_LEAF_MATRIX;
}
dim.width = required_matrix_width (w);
dim.height = required_matrix_height (w);
if (x != w->desired_matrix->matrix_x
|| y != w->desired_matrix->matrix_y
|| dim.width != w->desired_matrix->matrix_w
|| dim.height != w->desired_matrix->matrix_h
|| (margin_glyphs_to_reserve (w, dim.width,
w->left_margin_cols)
!= w->desired_matrix->left_margin_glyphs)
|| (margin_glyphs_to_reserve (w, dim.width,
w->right_margin_cols)
!= w->desired_matrix->right_margin_glyphs))
*window_change_flags |= CHANGED_LEAF_MATRIX;
if (!dim_only_p)
{
adjust_glyph_matrix (w, w->desired_matrix, x, y, dim);
adjust_glyph_matrix (w, w->current_matrix, x, y, dim);
}
}
if (in_horz_combination_p)
x += dim.width;
else
y += dim.height;
wmax = max (wmax, dim.width);
hmax = max (hmax, dim.height);
window = w->next;
}
while (!NILP (window));
if (in_horz_combination_p)
{
total.width = x - x0;
total.height = hmax;
}
else
{
total.width = wmax;
total.height = y - y0;
}
return total;
}
int
required_matrix_height (w)
struct window *w;
{
#ifdef HAVE_WINDOW_SYSTEM
struct frame *f = XFRAME (w->frame);
if (FRAME_WINDOW_P (f))
{
int ch_height = FRAME_SMALLEST_FONT_HEIGHT (f);
int window_pixel_height = window_box_height (w) + abs (w->vscroll);
return (((window_pixel_height + ch_height - 1)
/ ch_height) * w->nrows_scale_factor
+ 2
+ 2);
}
#endif
return WINDOW_TOTAL_LINES (w);
}
int
required_matrix_width (w)
struct window *w;
{
#ifdef HAVE_WINDOW_SYSTEM
struct frame *f = XFRAME (w->frame);
if (FRAME_WINDOW_P (f))
{
int ch_width = FRAME_SMALLEST_CHAR_WIDTH (f);
int window_pixel_width = WINDOW_TOTAL_WIDTH (w);
return (((window_pixel_width + ch_width - 1)
/ ch_width) * w->ncols_scale_factor
+ 2
+ 1 + 1);
}
#endif
return XINT (w->total_cols);
}
static void
allocate_matrices_for_window_redisplay (w)
struct window *w;
{
while (w)
{
if (!NILP (w->vchild))
allocate_matrices_for_window_redisplay (XWINDOW (w->vchild));
else if (!NILP (w->hchild))
allocate_matrices_for_window_redisplay (XWINDOW (w->hchild));
else
{
struct dim dim;
if (w->desired_matrix == NULL)
{
w->desired_matrix = new_glyph_matrix (NULL);
w->current_matrix = new_glyph_matrix (NULL);
}
dim.width = required_matrix_width (w);
dim.height = required_matrix_height (w);
adjust_glyph_matrix (w, w->desired_matrix, 0, 0, dim);
adjust_glyph_matrix (w, w->current_matrix, 0, 0, dim);
}
w = NILP (w->next) ? NULL : XWINDOW (w->next);
}
}
void
adjust_glyphs (f)
struct frame *f;
{
BLOCK_INPUT;
if (f)
adjust_frame_glyphs (f);
else
{
Lisp_Object tail, lisp_frame;
FOR_EACH_FRAME (tail, lisp_frame)
adjust_frame_glyphs (XFRAME (lisp_frame));
}
UNBLOCK_INPUT;
}
static void
adjust_frame_glyphs_initially ()
{
struct frame *sf = SELECTED_FRAME ();
struct window *root = XWINDOW (sf->root_window);
struct window *mini = XWINDOW (root->next);
int frame_lines = FRAME_LINES (sf);
int frame_cols = FRAME_COLS (sf);
int top_margin = FRAME_TOP_MARGIN (sf);
XSETFASTINT (root->top_line, top_margin);
XSETFASTINT (root->total_cols, frame_cols);
set_window_height (sf->root_window, frame_lines - 1 - top_margin, 0);
XSETFASTINT (mini->top_line, frame_lines - 1);
XSETFASTINT (mini->total_cols, frame_cols);
set_window_height (root->next, 1, 0);
adjust_frame_glyphs (sf);
glyphs_initialized_initially_p = 1;
}
static void
adjust_frame_glyphs (f)
struct frame *f;
{
if (FRAME_WINDOW_P (f))
adjust_frame_glyphs_for_window_redisplay (f);
else
adjust_frame_glyphs_for_frame_redisplay (f);
adjust_frame_message_buffer (f);
adjust_decode_mode_spec_buffer (f);
f->glyphs_initialized_p = 1;
}
static int
showing_window_margins_p (w)
struct window *w;
{
while (w)
{
if (!NILP (w->hchild))
{
if (showing_window_margins_p (XWINDOW (w->hchild)))
return 1;
}
else if (!NILP (w->vchild))
{
if (showing_window_margins_p (XWINDOW (w->vchild)))
return 1;
}
else if (!NILP (w->left_margin_cols)
|| !NILP (w->right_margin_cols))
return 1;
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
return 0;
}
static void
fake_current_matrices (window)
Lisp_Object window;
{
struct window *w;
for (; !NILP (window); window = w->next)
{
w = XWINDOW (window);
if (!NILP (w->hchild))
fake_current_matrices (w->hchild);
else if (!NILP (w->vchild))
fake_current_matrices (w->vchild);
else
{
int i;
struct frame *f = XFRAME (w->frame);
struct glyph_matrix *m = w->current_matrix;
struct glyph_matrix *fm = f->current_matrix;
xassert (m->matrix_h == WINDOW_TOTAL_LINES (w));
xassert (m->matrix_w == WINDOW_TOTAL_COLS (w));
for (i = 0; i < m->matrix_h; ++i)
{
struct glyph_row *r = m->rows + i;
struct glyph_row *fr = fm->rows + i + WINDOW_TOP_EDGE_LINE (w);
xassert (r->glyphs[TEXT_AREA] >= fr->glyphs[TEXT_AREA]
&& r->glyphs[LAST_AREA] <= fr->glyphs[LAST_AREA]);
r->enabled_p = fr->enabled_p;
if (r->enabled_p)
{
r->used[LEFT_MARGIN_AREA] = m->left_margin_glyphs;
r->used[RIGHT_MARGIN_AREA] = m->right_margin_glyphs;
r->used[TEXT_AREA] = (m->matrix_w
- r->used[LEFT_MARGIN_AREA]
- r->used[RIGHT_MARGIN_AREA]);
r->mode_line_p = 0;
}
}
}
}
}
static struct glyph_matrix *
save_current_matrix (f)
struct frame *f;
{
int i;
struct glyph_matrix *saved;
saved = (struct glyph_matrix *) xmalloc (sizeof *saved);
bzero (saved, sizeof *saved);
saved->nrows = f->current_matrix->nrows;
saved->rows = (struct glyph_row *) xmalloc (saved->nrows
* sizeof *saved->rows);
bzero (saved->rows, saved->nrows * sizeof *saved->rows);
for (i = 0; i < saved->nrows; ++i)
{
struct glyph_row *from = f->current_matrix->rows + i;
struct glyph_row *to = saved->rows + i;
size_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
to->glyphs[TEXT_AREA] = (struct glyph *) xmalloc (nbytes);
bcopy (from->glyphs[TEXT_AREA], to->glyphs[TEXT_AREA], nbytes);
to->used[TEXT_AREA] = from->used[TEXT_AREA];
}
return saved;
}
static void
restore_current_matrix (f, saved)
struct frame *f;
struct glyph_matrix *saved;
{
int i;
for (i = 0; i < saved->nrows; ++i)
{
struct glyph_row *from = saved->rows + i;
struct glyph_row *to = f->current_matrix->rows + i;
size_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
bcopy (from->glyphs[TEXT_AREA], to->glyphs[TEXT_AREA], nbytes);
to->used[TEXT_AREA] = from->used[TEXT_AREA];
xfree (from->glyphs[TEXT_AREA]);
}
xfree (saved->rows);
xfree (saved);
}
static void
adjust_frame_glyphs_for_frame_redisplay (f)
struct frame *f;
{
struct dim matrix_dim;
int pool_changed_p;
int window_change_flags;
int top_window_y;
if (!FRAME_LIVE_P (f))
return;
top_window_y = FRAME_TOP_MARGIN (f);
if (f->desired_pool == NULL)
{
f->desired_pool = new_glyph_pool ();
f->current_pool = new_glyph_pool ();
}
if (f->desired_matrix == NULL)
{
f->desired_matrix = new_glyph_matrix (f->desired_pool);
f->current_matrix = new_glyph_matrix (f->current_pool);
}
window_change_flags = 0;
matrix_dim
= allocate_matrices_for_frame_redisplay (FRAME_ROOT_WINDOW (f),
0, top_window_y,
1,
&window_change_flags);
matrix_dim.height += top_window_y;
pool_changed_p = realloc_glyph_pool (f->desired_pool, matrix_dim);
realloc_glyph_pool (f->current_pool, matrix_dim);
if (pool_changed_p || window_change_flags)
{
allocate_matrices_for_frame_redisplay (FRAME_ROOT_WINDOW (f),
0, top_window_y, 0,
&window_change_flags);
xassert (matrix_dim.width == FRAME_COLS (f)
&& matrix_dim.height == FRAME_LINES (f));
if (display_completed
&& !FRAME_GARBAGED_P (f)
&& matrix_dim.width == f->current_matrix->matrix_w
&& matrix_dim.height == f->current_matrix->matrix_h
&& !showing_window_margins_p (XWINDOW (FRAME_ROOT_WINDOW (f))))
{
struct glyph_matrix *copy = save_current_matrix (f);
adjust_glyph_matrix (NULL, f->desired_matrix, 0, 0, matrix_dim);
adjust_glyph_matrix (NULL, f->current_matrix, 0, 0, matrix_dim);
restore_current_matrix (f, copy);
fake_current_matrices (FRAME_ROOT_WINDOW (f));
}
else
{
adjust_glyph_matrix (NULL, f->desired_matrix, 0, 0, matrix_dim);
adjust_glyph_matrix (NULL, f->current_matrix, 0, 0, matrix_dim);
SET_FRAME_GARBAGED (f);
}
}
}
static void
adjust_frame_glyphs_for_window_redisplay (f)
struct frame *f;
{
struct window *w;
xassert (FRAME_WINDOW_P (f) && FRAME_LIVE_P (f));
allocate_matrices_for_window_redisplay (XWINDOW (FRAME_ROOT_WINDOW (f)));
#ifdef HAVE_X_WINDOWS
#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
{
if (NILP (f->menu_bar_window))
{
f->menu_bar_window = make_window ();
w = XWINDOW (f->menu_bar_window);
XSETFRAME (w->frame, f);
w->pseudo_window_p = 1;
}
else
w = XWINDOW (f->menu_bar_window);
XSETFASTINT (w->top_line, 0);
XSETFASTINT (w->left_col, 0);
XSETFASTINT (w->total_lines, FRAME_MENU_BAR_LINES (f));
XSETFASTINT (w->total_cols, FRAME_TOTAL_COLS (f));
allocate_matrices_for_window_redisplay (w);
}
#endif
#endif
#ifndef USE_GTK
if (NILP (f->tool_bar_window))
{
f->tool_bar_window = make_window ();
w = XWINDOW (f->tool_bar_window);
XSETFRAME (w->frame, f);
w->pseudo_window_p = 1;
}
else
w = XWINDOW (f->tool_bar_window);
XSETFASTINT (w->top_line, FRAME_MENU_BAR_LINES (f));
XSETFASTINT (w->left_col, 0);
XSETFASTINT (w->total_lines, FRAME_TOOL_BAR_LINES (f));
XSETFASTINT (w->total_cols, FRAME_TOTAL_COLS (f));
allocate_matrices_for_window_redisplay (w);
#endif
}
static void
adjust_frame_message_buffer (f)
struct frame *f;
{
int size = FRAME_MESSAGE_BUF_SIZE (f) + 1;
if (FRAME_MESSAGE_BUF (f))
{
char *buffer = FRAME_MESSAGE_BUF (f);
char *new_buffer = (char *) xrealloc (buffer, size);
FRAME_MESSAGE_BUF (f) = new_buffer;
}
else
FRAME_MESSAGE_BUF (f) = (char *) xmalloc (size);
}
static void
adjust_decode_mode_spec_buffer (f)
struct frame *f;
{
f->decode_mode_spec_buffer
= (char *) xrealloc (f->decode_mode_spec_buffer,
FRAME_MESSAGE_BUF_SIZE (f) + 1);
}
void
free_glyphs (f)
struct frame *f;
{
if (f && f->glyphs_initialized_p)
{
BLOCK_INPUT;
f->glyphs_initialized_p = 0;
if (!NILP (f->root_window))
free_window_matrices (XWINDOW (f->root_window));
if (!NILP (f->menu_bar_window))
{
struct window *w = XWINDOW (f->menu_bar_window);
free_glyph_matrix (w->desired_matrix);
free_glyph_matrix (w->current_matrix);
w->desired_matrix = w->current_matrix = NULL;
f->menu_bar_window = Qnil;
}
if (!NILP (f->tool_bar_window))
{
struct window *w = XWINDOW (f->tool_bar_window);
free_glyph_matrix (w->desired_matrix);
free_glyph_matrix (w->current_matrix);
w->desired_matrix = w->current_matrix = NULL;
f->tool_bar_window = Qnil;
}
if (f->desired_matrix)
{
free_glyph_matrix (f->desired_matrix);
free_glyph_matrix (f->current_matrix);
f->desired_matrix = f->current_matrix = NULL;
}
if (f->desired_pool)
{
free_glyph_pool (f->desired_pool);
free_glyph_pool (f->current_pool);
f->desired_pool = f->current_pool = NULL;
}
UNBLOCK_INPUT;
}
}
void
free_window_matrices (w)
struct window *w;
{
while (w)
{
if (!NILP (w->hchild))
free_window_matrices (XWINDOW (w->hchild));
else if (!NILP (w->vchild))
free_window_matrices (XWINDOW (w->vchild));
else
{
free_glyph_matrix (w->current_matrix);
free_glyph_matrix (w->desired_matrix);
w->current_matrix = w->desired_matrix = NULL;
}
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
}
void
check_glyph_memory ()
{
Lisp_Object tail, frame;
FOR_EACH_FRAME (tail, frame)
free_glyphs (XFRAME (frame));
if (glyph_matrix_count)
abort ();
if (glyph_pool_count)
abort ();
}
static void
build_frame_matrix (f)
struct frame *f;
{
int i;
xassert (!FRAME_WINDOW_P (f));
for (i = FRAME_TOP_MARGIN (f); i < f->desired_matrix->nrows; ++i)
clear_glyph_row (MATRIX_ROW (f->desired_matrix, i));
build_frame_matrix_from_window_tree (f->desired_matrix,
XWINDOW (FRAME_ROOT_WINDOW (f)));
}
static void
build_frame_matrix_from_window_tree (matrix, w)
struct glyph_matrix *matrix;
struct window *w;
{
while (w)
{
if (!NILP (w->hchild))
build_frame_matrix_from_window_tree (matrix, XWINDOW (w->hchild));
else if (!NILP (w->vchild))
build_frame_matrix_from_window_tree (matrix, XWINDOW (w->vchild));
else
build_frame_matrix_from_leaf_window (matrix, w);
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
}
static void
build_frame_matrix_from_leaf_window (frame_matrix, w)
struct glyph_matrix *frame_matrix;
struct window *w;
{
struct glyph_matrix *window_matrix;
int window_y, frame_y;
GLYPH right_border_glyph = 0;
if (w->must_be_updated_p)
{
window_matrix = w->desired_matrix;
if (!WINDOW_RIGHTMOST_P (w))
{
struct Lisp_Char_Table *dp = window_display_table (w);
right_border_glyph
= ((dp && INTEGERP (DISP_BORDER_GLYPH (dp)))
? spec_glyph_lookup_face (w, XINT (DISP_BORDER_GLYPH (dp)))
: '|');
if (FAST_GLYPH_FACE (right_border_glyph) <= 0)
right_border_glyph
= FAST_MAKE_GLYPH (right_border_glyph, VERTICAL_BORDER_FACE_ID);
}
}
else
window_matrix = w->current_matrix;
window_y = 0;
frame_y = window_matrix->matrix_y;
while (window_y < window_matrix->nrows)
{
struct glyph_row *frame_row = frame_matrix->rows + frame_y;
struct glyph_row *window_row = window_matrix->rows + window_y;
int current_row_p = window_matrix == w->current_matrix;
fill_up_frame_row_with_spaces (frame_row, window_matrix->matrix_x);
fill_up_glyph_row_with_spaces (window_row);
if (window_matrix == w->desired_matrix
&& !window_row->enabled_p)
{
window_row = w->current_matrix->rows + window_y;
current_row_p = 1;
}
if (current_row_p)
{
bcopy (window_row->glyphs[0],
frame_row->glyphs[TEXT_AREA] + window_matrix->matrix_x,
window_matrix->matrix_w * sizeof (struct glyph));
}
else
{
xassert (window_row->enabled_p);
frame_row->enabled_p = 1;
if (right_border_glyph)
{
struct glyph *border = window_row->glyphs[LAST_AREA] - 1;
SET_CHAR_GLYPH_FROM_GLYPH (*border, right_border_glyph);
}
#if GLYPH_DEBUG
xassert (glyph_row_slice_p (window_row, frame_row));
strcpy (w->current_matrix->method, w->desired_matrix->method);
add_window_display_history (w, w->current_matrix->method, 0);
#endif
}
frame_row->used[TEXT_AREA]
= window_matrix->matrix_x + window_matrix->matrix_w;
++window_y;
++frame_y;
}
}
GLYPH
spec_glyph_lookup_face (w, glyph)
struct window *w;
GLYPH glyph;
{
int lface_id = FAST_GLYPH_FACE (glyph);
if (lface_id > 0)
{
int face_id = merge_faces (XFRAME (w->frame),
Qt, lface_id, DEFAULT_FACE_ID);
glyph
= FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), face_id);
}
return glyph;
}
static void
fill_up_glyph_row_with_spaces (row)
struct glyph_row *row;
{
fill_up_glyph_row_area_with_spaces (row, LEFT_MARGIN_AREA);
fill_up_glyph_row_area_with_spaces (row, TEXT_AREA);
fill_up_glyph_row_area_with_spaces (row, RIGHT_MARGIN_AREA);
}
static void
fill_up_glyph_row_area_with_spaces (row, area)
struct glyph_row *row;
int area;
{
if (row->glyphs[area] < row->glyphs[area + 1])
{
struct glyph *end = row->glyphs[area + 1];
struct glyph *text = row->glyphs[area] + row->used[area];
while (text < end)
*text++ = space_glyph;
row->used[area] = text - row->glyphs[area];
}
}
static void
fill_up_frame_row_with_spaces (row, upto)
struct glyph_row *row;
int upto;
{
int i = row->used[TEXT_AREA];
struct glyph *glyph = row->glyphs[TEXT_AREA];
while (i < upto)
glyph[i++] = space_glyph;
row->used[TEXT_AREA] = i;
}
static INLINE void
set_frame_matrix_frame (f)
struct frame *f;
{
frame_matrix_frame = f;
}
static INLINE void
make_current (desired_matrix, current_matrix, row)
struct glyph_matrix *desired_matrix, *current_matrix;
int row;
{
struct glyph_row *current_row = MATRIX_ROW (current_matrix, row);
struct glyph_row *desired_row = MATRIX_ROW (desired_matrix, row);
int mouse_face_p = current_row->mouse_face_p;
assign_row (current_row, desired_row);
current_row->enabled_p = 1;
current_row->mouse_face_p = mouse_face_p;
if (frame_matrix_frame)
mirror_make_current (XWINDOW (frame_matrix_frame->root_window), row);
}
static void
mirror_make_current (w, frame_row)
struct window *w;
int frame_row;
{
while (w)
{
if (!NILP (w->hchild))
mirror_make_current (XWINDOW (w->hchild), frame_row);
else if (!NILP (w->vchild))
mirror_make_current (XWINDOW (w->vchild), frame_row);
else
{
int row = frame_row - w->desired_matrix->matrix_y;
if (row >= 0 && row < w->desired_matrix->matrix_h)
{
struct glyph_row *current_row
= MATRIX_ROW (w->current_matrix, row);
struct glyph_row *desired_row
= MATRIX_ROW (w->desired_matrix, row);
if (desired_row->enabled_p)
assign_row (current_row, desired_row);
else
swap_glyph_pointers (desired_row, current_row);
current_row->enabled_p = 1;
}
}
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
}
void
mirrored_line_dance (matrix, unchanged_at_top, nlines, copy_from,
retained_p)
struct glyph_matrix *matrix;
int unchanged_at_top, nlines;
int *copy_from;
char *retained_p;
{
struct glyph_row *old_rows;
struct glyph_row *new_rows = MATRIX_ROW (matrix, unchanged_at_top);
int i;
old_rows = (struct glyph_row *) alloca (nlines * sizeof *old_rows);
bcopy (new_rows, old_rows, nlines * sizeof *old_rows);
for (i = 0; i < nlines; ++i)
{
int enabled_before_p = new_rows[i].enabled_p;
xassert (i + unchanged_at_top < matrix->nrows);
xassert (unchanged_at_top + copy_from[i] < matrix->nrows);
new_rows[i] = old_rows[copy_from[i]];
new_rows[i].enabled_p = enabled_before_p;
if (!retained_p[copy_from[i]])
new_rows[i].enabled_p = 0;
}
if (frame_matrix_frame)
mirror_line_dance (XWINDOW (frame_matrix_frame->root_window),
unchanged_at_top, nlines, copy_from, retained_p);
}
static void
sync_window_with_frame_matrix_rows (w)
struct window *w;
{
struct frame *f = XFRAME (w->frame);
struct glyph_row *window_row, *window_row_end, *frame_row;
int left, right, x, width;
xassert (NILP (w->hchild) && NILP (w->vchild));
xassert (!FRAME_WINDOW_P (f));
left = margin_glyphs_to_reserve (w, 1, w->left_margin_cols);
right = margin_glyphs_to_reserve (w, 1, w->right_margin_cols);
x = w->current_matrix->matrix_x;
width = w->current_matrix->matrix_w;
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);
for (; window_row < window_row_end; ++window_row, ++frame_row)
{
window_row->glyphs[LEFT_MARGIN_AREA]
= frame_row->glyphs[0] + x;
window_row->glyphs[TEXT_AREA]
= window_row->glyphs[LEFT_MARGIN_AREA] + left;
window_row->glyphs[LAST_AREA]
= window_row->glyphs[LEFT_MARGIN_AREA] + width;
window_row->glyphs[RIGHT_MARGIN_AREA]
= window_row->glyphs[LAST_AREA] - right;
}
}
struct window *
frame_row_to_window (w, row)
struct window *w;
int row;
{
struct window *found = NULL;
while (w && !found)
{
if (!NILP (w->hchild))
found = frame_row_to_window (XWINDOW (w->hchild), row);
else if (!NILP (w->vchild))
found = frame_row_to_window (XWINDOW (w->vchild), row);
else if (row >= WINDOW_TOP_EDGE_LINE (w)
&& row < WINDOW_BOTTOM_EDGE_LINE (w))
found = w;
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
return found;
}
static void
mirror_line_dance (w, unchanged_at_top, nlines, copy_from, retained_p)
struct window *w;
int unchanged_at_top, nlines;
int *copy_from;
char *retained_p;
{
while (w)
{
if (!NILP (w->hchild))
mirror_line_dance (XWINDOW (w->hchild), unchanged_at_top,
nlines, copy_from, retained_p);
else if (!NILP (w->vchild))
mirror_line_dance (XWINDOW (w->vchild), unchanged_at_top,
nlines, copy_from, retained_p);
else
{
struct glyph_matrix *m = w->current_matrix;
int i, sync_p = 0;
struct glyph_row *old_rows;
old_rows = (struct glyph_row *) alloca (m->nrows * sizeof *old_rows);
bcopy (m->rows, old_rows, m->nrows * sizeof *old_rows);
for (i = 0; i < nlines; ++i)
{
int frame_to = i + unchanged_at_top;
int frame_from = copy_from[i] + unchanged_at_top;
int window_to = frame_to - m->matrix_y;
int window_from = frame_from - m->matrix_y;
int from_inside_window_p
= window_from >= 0 && window_from < m->matrix_h;
int to_inside_window_p
= window_to >= 0 && window_to < m->matrix_h;
if (from_inside_window_p && to_inside_window_p)
{
int enabled_before_p;
enabled_before_p = m->rows[window_to].enabled_p;
m->rows[window_to] = old_rows[window_from];
m->rows[window_to].enabled_p = enabled_before_p;
if (!retained_p[copy_from[i]])
m->rows[window_to].enabled_p = 0;
}
else if (to_inside_window_p)
{
struct frame *f = XFRAME (w->frame);
struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
struct window *w2;
struct glyph_matrix *m2;
int m2_from;
w2 = frame_row_to_window (root, frame_from);
if (w2)
{
m2 = w2->current_matrix;
m2_from = frame_from - m2->matrix_y;
copy_row_except_pointers (m->rows + window_to,
m2->rows + m2_from);
if (!retained_p[copy_from[i]])
m->rows[window_to].enabled_p = 0;
}
sync_p = 1;
}
else if (from_inside_window_p)
sync_p = 1;
}
if (sync_p)
sync_window_with_frame_matrix_rows (w);
CHECK_MATRIX (m);
}
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
}
#if GLYPH_DEBUG
void
check_window_matrix_pointers (w)
struct window *w;
{
while (w)
{
if (!NILP (w->hchild))
check_window_matrix_pointers (XWINDOW (w->hchild));
else if (!NILP (w->vchild))
check_window_matrix_pointers (XWINDOW (w->vchild));
else
{
struct frame *f = XFRAME (w->frame);
check_matrix_pointers (w->desired_matrix, f->desired_matrix);
check_matrix_pointers (w->current_matrix, f->current_matrix);
}
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
}
static void
check_matrix_pointers (window_matrix, frame_matrix)
struct glyph_matrix *window_matrix, *frame_matrix;
{
int i = 0;
int j = window_matrix->matrix_y;
while (i < window_matrix->nrows)
{
if (!glyph_row_slice_p (window_matrix->rows + i,
frame_matrix->rows + j))
abort ();
++i, ++j;
}
}
#endif
#if GLYPH_DEBUG
static int
window_to_frame_vpos (w, vpos)
struct window *w;
int vpos;
{
struct frame *f = XFRAME (w->frame);
xassert (!FRAME_WINDOW_P (f));
xassert (vpos >= 0 && vpos <= w->desired_matrix->nrows);
vpos += WINDOW_TOP_EDGE_LINE (w);
xassert (vpos >= 0 && vpos <= FRAME_LINES (f));
return vpos;
}
static int
window_to_frame_hpos (w, hpos)
struct window *w;
int hpos;
{
xassert (!FRAME_WINDOW_P (XFRAME (w->frame)));
hpos += WINDOW_LEFT_EDGE_COL (w);
return hpos;
}
#endif
DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0,
doc: )
(frame)
Lisp_Object frame;
{
struct frame *f;
CHECK_LIVE_FRAME (frame);
f = XFRAME (frame);
if (!glyphs_initialized_initially_p)
return Qnil;
update_begin (f);
if (FRAME_MSDOS_P (f))
set_terminal_modes ();
clear_frame ();
clear_current_matrices (f);
update_end (f);
fflush (stdout);
windows_or_buffers_changed++;
mark_window_display_accurate (FRAME_ROOT_WINDOW (f), 0);
set_window_update_flags (XWINDOW (FRAME_ROOT_WINDOW (f)), 1);
f->garbaged = 0;
return Qnil;
}
void
redraw_frame (f)
struct frame *f;
{
Lisp_Object frame;
XSETFRAME (frame, f);
Fredraw_frame (frame);
}
DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "",
doc: )
()
{
Lisp_Object tail, frame;
FOR_EACH_FRAME (tail, frame)
if (FRAME_VISIBLE_P (XFRAME (frame)))
Fredraw_frame (frame);
return Qnil;
}
void
redraw_garbaged_frames ()
{
Lisp_Object tail, frame;
FOR_EACH_FRAME (tail, frame)
if (FRAME_VISIBLE_P (XFRAME (frame))
&& FRAME_GARBAGED_P (XFRAME (frame)))
Fredraw_frame (frame);
}
int
direct_output_for_insert (g)
int g;
{
register struct frame *f = SELECTED_FRAME ();
struct window *w = XWINDOW (selected_window);
struct it it, it2;
struct glyph_row *glyph_row;
struct glyph *glyphs, *glyph, *end;
int n;
int window_redisplay_p = FRAME_WINDOW_P (f);
int overwrite_p = !NILP (current_buffer->overwrite_mode);
int added_width;
struct text_pos pos;
int delta, delta_bytes;
redisplay_performed_directly_p = 0;
if (cursor_in_echo_area
|| fonts_changed_p
|| face_change_count
|| !display_completed
|| buffer_shared > 1
|| (EQ (selected_window, minibuf_window)
&& EQ (minibuf_window, echo_area_window))
|| (MINI_WINDOW_P (w) && XFASTINT (w->hscroll))
|| (overwrite_p
&& PT != ZV
&& FETCH_BYTE (PT) != '\n')
|| g == '\t'
|| g == '\n'
|| g == '\r'
|| w->cursor.vpos < 0
|| !NILP (echo_area_buffer[0])
|| !NILP (echo_area_buffer[1])
|| (glyph_row = MATRIX_ROW (w->current_matrix, w->cursor.vpos),
(glyph_row->continued_p
|| glyph_row->exact_window_width_line_p
|| glyph_row->overlapping_p
|| glyph_row->overlapped_p))
|| (!window_redisplay_p && !WINDOW_FULL_WIDTH_P (w)))
return 0;
if (!char_ins_del_ok)
if (PT != ZV && FETCH_BYTE (PT_BYTE) != '\n')
return 0;
clear_glyph_row (&scratch_glyph_row);
SET_TEXT_POS (pos, PT, PT_BYTE);
DEC_TEXT_POS (pos, !NILP (current_buffer->enable_multibyte_characters));
init_iterator (&it, w, CHARPOS (pos), BYTEPOS (pos), &scratch_glyph_row,
DEFAULT_FACE_ID);
glyph_row = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
if (glyph_row->mouse_face_p)
return 0;
if (!NILP (Vshow_trailing_whitespace)
&& glyph_row->used[TEXT_AREA])
{
struct glyph *last;
last = glyph_row->glyphs[TEXT_AREA] + glyph_row->used[TEXT_AREA] - 1;
if (last->type == STRETCH_GLYPH
|| (last->type == CHAR_GLYPH
&& last->u.ch == ' '))
return 0;
}
if (STRINGP (it.string))
return 0;
it.hpos = w->cursor.hpos;
it.vpos = w->cursor.vpos;
it.current_x = w->cursor.x + it.first_visible_x;
it.current_y = w->cursor.y;
it.end_charpos = PT;
it.stop_charpos = min (PT, it.stop_charpos);
it.stop_charpos = max (IT_CHARPOS (it), it.stop_charpos);
delta = delta_bytes = 0;
while (get_next_display_element (&it))
{
PRODUCE_GLYPHS (&it);
if (it.current_x >= it.last_visible_x)
return 0;
if (glyph_row->ascent != it.ascent
|| glyph_row->height != it.ascent + it.descent
|| glyph_row->phys_ascent != it.phys_ascent
|| glyph_row->phys_height != it.phys_ascent + it.phys_descent
|| it.what != IT_CHARACTER)
return 0;
delta += 1;
delta_bytes += it.len;
set_iterator_to_next (&it, 1);
}
added_width = it.current_x - (w->cursor.x + it.first_visible_x);
if (glyph_row->pixel_width + added_width >= it.last_visible_x)
return 0;
it2 = it;
it2.end_charpos = ZV;
it2.stop_charpos = min (it2.stop_charpos, ZV);
while (get_next_display_element (&it2)
&& !ITERATOR_AT_END_OF_LINE_P (&it2))
{
if (it2.c == '\t')
return 0;
set_iterator_to_next (&it2, 1);
}
n = it.glyph_row->used[TEXT_AREA];
glyphs = glyph_row->glyphs[TEXT_AREA] + w->cursor.hpos;
end = glyph_row->glyphs[1 + TEXT_AREA];
xassert (end - glyphs - n >= 0);
safe_bcopy ((char *) glyphs, (char *) (glyphs + n),
(end - glyphs - n) * sizeof (*end));
bcopy (it.glyph_row->glyphs[TEXT_AREA], glyphs, n * sizeof *glyphs);
glyph_row->used[TEXT_AREA] = min (glyph_row->used[TEXT_AREA] + n,
end - glyph_row->glyphs[TEXT_AREA]);
glyph = glyph_row->glyphs[TEXT_AREA];
end = glyph + glyph_row->used[TEXT_AREA];
glyph_row->pixel_width = glyph_row->x;
while (glyph < end)
{
glyph_row->pixel_width += glyph->pixel_width;
++glyph;
}
for (glyph = glyphs + n; glyph < end; ++glyph)
if (glyph->charpos > 0 && BUFFERP (glyph->object))
glyph->charpos += delta;
if (MATRIX_ROW_END_CHARPOS (glyph_row) > 0)
{
MATRIX_ROW_END_CHARPOS (glyph_row) += delta;
MATRIX_ROW_END_BYTEPOS (glyph_row) += delta_bytes;
}
increment_matrix_positions (w->current_matrix,
w->cursor.vpos + 1,
w->current_matrix->nrows,
delta, delta_bytes);
glyph_row->contains_overlapping_glyphs_p
|= it.glyph_row->contains_overlapping_glyphs_p;
glyph_row->displays_text_p = 1;
w->window_end_vpos = make_number (max (w->cursor.vpos,
XFASTINT (w->window_end_vpos)));
if (!NILP (Vshow_trailing_whitespace))
highlight_trailing_whitespace (it.f, glyph_row);
updated_row = glyph_row;
updated_area = TEXT_AREA;
update_begin (f);
if (rif)
{
rif->update_window_begin_hook (w);
if (glyphs == end - n
|| (glyphs == end - n - 1
&& (end - n)->charpos <= 0))
rif->write_glyphs (glyphs, n);
else
rif->insert_glyphs (glyphs, n);
}
else
{
if (glyphs == end - n)
write_glyphs (glyphs, n);
else
insert_glyphs (glyphs, n);
}
w->cursor.hpos += n;
w->cursor.x = it.current_x - it.first_visible_x;
xassert (w->cursor.hpos >= 0
&& w->cursor.hpos < w->desired_matrix->matrix_w);
if (window_redisplay_p)
rif->cursor_to (w->cursor.vpos, w->cursor.hpos,
w->cursor.y, w->cursor.x);
else
{
int x, y;
x = (WINDOW_TO_FRAME_HPOS (w, w->cursor.hpos)
+ (INTEGERP (w->left_margin_cols)
? XFASTINT (w->left_margin_cols)
: 0));
y = WINDOW_TO_FRAME_VPOS (w, w->cursor.vpos);
cursor_to (y, x);
}
#ifdef HAVE_WINDOW_SYSTEM
update_window_fringes (w, 0);
#endif
if (rif)
rif->update_window_end_hook (w, 1, 0);
update_end (f);
updated_row = NULL;
fflush (stdout);
TRACE ((stderr, "direct output for insert\n"));
mark_window_display_accurate (it.window, 1);
redisplay_performed_directly_p = 1;
return 1;
}
int
direct_output_forward_char (n)
int n;
{
struct frame *f = SELECTED_FRAME ();
struct window *w = XWINDOW (selected_window);
struct glyph_row *row;
if (check_point_in_composition (current_buffer, XINT (w->last_point),
current_buffer, PT))
return 0;
if (face_change_count)
return 0;
if (!display_completed || cursor_in_echo_area)
return 0;
if (!NILP (XBUFFER (w->buffer)->direction_reversed))
return 0;
if (!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
return 0;
if (!NILP (Vshow_trailing_whitespace))
return 0;
if (!NILP (echo_area_buffer[0]) || !NILP (echo_area_buffer[1]))
return 0;
if (XWINDOW (minibuf_window) == w
&& EQ (minibuf_window, echo_area_window))
return 0;
if (w->cursor.vpos < 0)
return 0;
row = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
if (PT <= MATRIX_ROW_START_CHARPOS (row)
|| PT >= MATRIX_ROW_END_CHARPOS (row))
return 0;
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
w->last_cursor = w->cursor;
XSETFASTINT (w->last_point, PT);
xassert (w->cursor.hpos >= 0
&& w->cursor.hpos < w->desired_matrix->matrix_w);
if (FRAME_WINDOW_P (f))
rif->cursor_to (w->cursor.vpos, w->cursor.hpos,
w->cursor.y, w->cursor.x);
else
{
int x, y;
x = (WINDOW_TO_FRAME_HPOS (w, w->cursor.hpos)
+ (INTEGERP (w->left_margin_cols)
? XFASTINT (w->left_margin_cols)
: 0));
y = WINDOW_TO_FRAME_VPOS (w, w->cursor.vpos);
cursor_to (y, x);
}
fflush (stdout);
redisplay_performed_directly_p = 1;
return 1;
}
int
update_frame (f, force_p, inhibit_hairy_id_p)
struct frame *f;
int force_p;
int inhibit_hairy_id_p;
{
int paused_p;
struct window *root_window = XWINDOW (f->root_window);
if (redisplay_dont_pause)
force_p = 1;
#if PERIODIC_PREEMPTION_CHECKING
else if (NILP (Vredisplay_preemption_period))
force_p = 1;
else if (!force_p && NUMBERP (Vredisplay_preemption_period))
{
EMACS_TIME tm;
double p = XFLOATINT (Vredisplay_preemption_period);
int sec, usec;
if (detect_input_pending_ignore_squeezables ())
{
paused_p = 1;
goto do_pause;
}
sec = (int) p;
usec = (p - sec) * 1000000;
EMACS_GET_TIME (tm);
EMACS_SET_SECS_USECS (preemption_period, sec, usec);
EMACS_ADD_TIME (preemption_next_check, tm, preemption_period);
}
#endif
if (FRAME_WINDOW_P (f))
{
set_frame_matrix_frame (NULL);
update_begin (f);
if (WINDOWP (f->menu_bar_window))
update_window (XWINDOW (f->menu_bar_window), 1);
if (WINDOWP (f->tool_bar_window))
{
struct window *w = XWINDOW (f->tool_bar_window);
if (w->must_be_updated_p)
{
Lisp_Object tem;
update_window (w, 1);
w->must_be_updated_p = 0;
tem = f->current_tool_bar_string;
f->current_tool_bar_string = f->desired_tool_bar_string;
f->desired_tool_bar_string = tem;
}
}
paused_p = update_window_tree (root_window, force_p);
update_end (f);
if (f->force_flush_display_p)
{
rif->flush_display (f);
f->force_flush_display_p = 0;
}
}
else
{
set_frame_matrix_frame (f);
build_frame_matrix (f);
update_begin (f);
paused_p = update_frame_1 (f, force_p, inhibit_hairy_id_p);
update_end (f);
if (termscript)
fflush (termscript);
fflush (stdout);
#if GLYPH_DEBUG
check_window_matrix_pointers (root_window);
add_frame_display_history (f, paused_p);
#endif
}
do_pause:
set_window_update_flags (root_window, 0);
display_completed = !paused_p;
return paused_p;
}
static int
update_window_tree (w, force_p)
struct window *w;
int force_p;
{
int paused_p = 0;
while (w && !paused_p)
{
if (!NILP (w->hchild))
paused_p |= update_window_tree (XWINDOW (w->hchild), force_p);
else if (!NILP (w->vchild))
paused_p |= update_window_tree (XWINDOW (w->vchild), force_p);
else if (w->must_be_updated_p)
paused_p |= update_window (w, force_p);
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
return paused_p;
}
void
update_single_window (w, force_p)
struct window *w;
int force_p;
{
if (w->must_be_updated_p)
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
set_frame_matrix_frame (NULL);
if (redisplay_dont_pause)
force_p = 1;
#if PERIODIC_PREEMPTION_CHECKING
else if (NILP (Vredisplay_preemption_period))
force_p = 1;
else if (!force_p && NUMBERP (Vredisplay_preemption_period))
{
EMACS_TIME tm;
double p = XFLOATINT (Vredisplay_preemption_period);
int sec, usec;
sec = (int) p;
usec = (p - sec) * 1000000;
EMACS_GET_TIME (tm);
EMACS_SET_SECS_USECS (preemption_period, sec, usec);
EMACS_ADD_TIME (preemption_next_check, tm, preemption_period);
}
#endif
update_begin (f);
update_window (w, force_p);
update_end (f);
w->must_be_updated_p = 0;
}
}
#ifdef HAVE_WINDOW_SYSTEM
static void
redraw_overlapped_rows (w, yb)
struct window *w;
int yb;
{
int i;
for (i = 0; i < w->current_matrix->nrows; ++i)
{
struct glyph_row *row = w->current_matrix->rows + i;
if (!row->enabled_p)
break;
else if (row->mode_line_p)
continue;
if (row->overlapped_p)
{
enum glyph_row_area area;
for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
{
updated_row = row;
updated_area = area;
rif->cursor_to (i, 0, row->y, area == TEXT_AREA ? row->x : 0);
if (row->used[area])
rif->write_glyphs (row->glyphs[area], row->used[area]);
rif->clear_end_of_line (-1);
}
row->overlapped_p = 0;
}
if (MATRIX_ROW_BOTTOM_Y (row) >= yb)
break;
}
}
static void
redraw_overlapping_rows (w, yb)
struct window *w;
int yb;
{
int i, bottom_y;
struct glyph_row *row;
for (i = 0; i < w->current_matrix->nrows; ++i)
{
row = w->current_matrix->rows + i;
if (!row->enabled_p)
break;
else if (row->mode_line_p)
continue;
bottom_y = MATRIX_ROW_BOTTOM_Y (row);
if (row->overlapping_p && i > 0 && bottom_y < yb)
{
int overlaps = 0;
if (MATRIX_ROW_OVERLAPS_PRED_P (row)
&& !MATRIX_ROW (w->current_matrix, i - 1)->overlapped_p)
overlaps |= OVERLAPS_PRED;
if (MATRIX_ROW_OVERLAPS_SUCC_P (row)
&& !MATRIX_ROW (w->current_matrix, i + 1)->overlapped_p)
overlaps |= OVERLAPS_SUCC;
if (overlaps)
{
if (row->used[LEFT_MARGIN_AREA])
rif->fix_overlapping_area (w, row, LEFT_MARGIN_AREA, overlaps);
if (row->used[TEXT_AREA])
rif->fix_overlapping_area (w, row, TEXT_AREA, overlaps);
if (row->used[RIGHT_MARGIN_AREA])
rif->fix_overlapping_area (w, row, RIGHT_MARGIN_AREA, overlaps);
if (overlaps & OVERLAPS_PRED)
MATRIX_ROW (w->current_matrix, i - 1)->overlapped_p = 1;
if (overlaps & OVERLAPS_SUCC)
MATRIX_ROW (w->current_matrix, i + 1)->overlapped_p = 1;
}
}
if (bottom_y >= yb)
break;
}
}
#endif
#ifdef GLYPH_DEBUG
void
check_current_matrix_flags (w)
struct window *w;
{
int last_seen_p = 0;
int i, yb = window_text_bottom_y (w);
for (i = 0; i < w->current_matrix->nrows - 1; ++i)
{
struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
if (!last_seen_p && MATRIX_ROW_BOTTOM_Y (row) >= yb)
last_seen_p = 1;
else if (last_seen_p && row->enabled_p)
abort ();
}
}
#endif
static int
update_window (w, force_p)
struct window *w;
int force_p;
{
struct glyph_matrix *desired_matrix = w->desired_matrix;
int paused_p;
#if !PERIODIC_PREEMPTION_CHECKING
int preempt_count = baud_rate / 2400 + 1;
#endif
extern int input_pending;
extern Lisp_Object do_mouse_tracking;
#if GLYPH_DEBUG
xassert (FRAME_WINDOW_P (XFRAME (WINDOW_FRAME (w))));
xassert (updating_frame != NULL);
#endif
#if !PERIODIC_PREEMPTION_CHECKING
if (!force_p)
detect_input_pending_ignore_squeezables ();
#endif
if (force_p || !input_pending || !NILP (do_mouse_tracking))
{
struct glyph_row *row, *end;
struct glyph_row *mode_line_row;
struct glyph_row *header_line_row;
int yb, changed_p = 0, mouse_face_overwritten_p = 0, n_updated;
rif->update_window_begin_hook (w);
yb = window_text_bottom_y (w);
row = desired_matrix->rows;
end = row + desired_matrix->nrows - 1;
if (row->mode_line_p)
{
header_line_row = row;
++row;
}
else
header_line_row = NULL;
mode_line_row = MATRIX_MODE_LINE_ROW (desired_matrix);
if (mode_line_row->mode_line_p && mode_line_row->enabled_p)
{
mode_line_row->y = yb;
update_window_line (w, MATRIX_ROW_VPOS (mode_line_row,
desired_matrix),
&mouse_face_overwritten_p);
}
while (row < end && !row->enabled_p)
++row;
if (row < end && !desired_matrix->no_scrolling_p)
{
int rc = scrolling_window (w, header_line_row != NULL);
if (rc < 0)
{
paused_p = 0;
goto set_cursor;
}
else if (rc > 0)
{
force_p = 1;
changed_p = 1;
}
}
for (n_updated = 0; row < end && (force_p || !input_pending); ++row)
if (row->enabled_p)
{
int vpos = MATRIX_ROW_VPOS (row, desired_matrix);
int i;
#if PERIODIC_PREEMPTION_CHECKING
if (!force_p)
{
EMACS_TIME tm, dif;
EMACS_GET_TIME (tm);
EMACS_SUB_TIME (dif, preemption_next_check, tm);
if (EMACS_TIME_NEG_P (dif))
{
EMACS_ADD_TIME (preemption_next_check, tm, preemption_period);
if (detect_input_pending_ignore_squeezables ())
break;
}
}
#else
if (!force_p && ++n_updated % preempt_count == 0)
detect_input_pending_ignore_squeezables ();
#endif
changed_p |= update_window_line (w, vpos,
&mouse_face_overwritten_p);
if (MATRIX_ROW_BOTTOM_Y (row) >= yb)
for (i = vpos + 1; i < w->current_matrix->nrows - 1; ++i)
MATRIX_ROW (w->current_matrix, i)->enabled_p = 0;
}
paused_p = row < end;
set_cursor:
if (header_line_row && header_line_row->enabled_p)
{
header_line_row->y = 0;
update_window_line (w, 0, &mouse_face_overwritten_p);
}
if (!paused_p && !w->pseudo_window_p)
{
#ifdef HAVE_WINDOW_SYSTEM
if (changed_p && rif->fix_overlapping_area)
{
redraw_overlapped_rows (w, yb);
redraw_overlapping_rows (w, yb);
}
#endif
set_window_cursor_after_update (w);
#if 0
IF_DEBUG (check_matrix_invariants (w));
#endif
}
#if GLYPH_DEBUG
strcpy (w->current_matrix->method, w->desired_matrix->method);
#endif
#ifdef HAVE_WINDOW_SYSTEM
update_window_fringes (w, 0);
#endif
rif->update_window_end_hook (w, !paused_p, mouse_face_overwritten_p);
}
else
paused_p = 1;
#if GLYPH_DEBUG
add_window_display_history (w, w->current_matrix->method, paused_p);
#endif
clear_glyph_matrix (desired_matrix);
return paused_p;
}
static void
update_marginal_area (w, area, vpos)
struct window *w;
int area, vpos;
{
struct glyph_row *desired_row = MATRIX_ROW (w->desired_matrix, vpos);
updated_area = area;
rif->cursor_to (vpos, 0, desired_row->y, 0);
if (desired_row->used[area])
rif->write_glyphs (desired_row->glyphs[area], desired_row->used[area]);
rif->clear_end_of_line (-1);
}
static int
update_text_area (w, vpos)
struct window *w;
int vpos;
{
struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, vpos);
struct glyph_row *desired_row = MATRIX_ROW (w->desired_matrix, vpos);
int changed_p = 0;
updated_area = TEXT_AREA;
if (!current_row->enabled_p
|| desired_row->y != current_row->y
|| desired_row->ascent != current_row->ascent
|| desired_row->phys_ascent != current_row->phys_ascent
|| desired_row->phys_height != current_row->phys_height
|| desired_row->visible_height != current_row->visible_height
|| current_row->overlapped_p
|| (current_row->mouse_face_p
&& !(current_row->mode_line_p && vpos > 0))
|| current_row->x != desired_row->x)
{
rif->cursor_to (vpos, 0, desired_row->y, desired_row->x);
if (desired_row->used[TEXT_AREA])
rif->write_glyphs (desired_row->glyphs[TEXT_AREA],
desired_row->used[TEXT_AREA]);
rif->clear_end_of_line (-1);
changed_p = 1;
if (vpos == w->phys_cursor.vpos)
w->phys_cursor_on_p = 0;
}
else
{
int stop, i, x;
struct glyph *current_glyph = current_row->glyphs[TEXT_AREA];
struct glyph *desired_glyph = desired_row->glyphs[TEXT_AREA];
int overlapping_glyphs_p = current_row->contains_overlapping_glyphs_p;
int desired_stop_pos = desired_row->used[TEXT_AREA];
if (MATRIX_ROW_EXTENDS_FACE_P (desired_row)
&& (desired_stop_pos < current_row->used[TEXT_AREA]
|| (desired_stop_pos == current_row->used[TEXT_AREA]
&& !MATRIX_ROW_EXTENDS_FACE_P (current_row))))
--desired_stop_pos;
stop = min (current_row->used[TEXT_AREA], desired_stop_pos);
i = 0;
x = desired_row->x;
while (i < stop)
{
int can_skip_p = 1;
if (overlapping_glyphs_p && i > 0)
{
struct glyph *glyph = ¤t_row->glyphs[TEXT_AREA][i - 1];
int left, right;
rif->get_glyph_overhangs (glyph, XFRAME (w->frame),
&left, &right);
can_skip_p = right == 0;
}
if (can_skip_p)
{
while (i < stop
&& GLYPH_EQUAL_P (desired_glyph, current_glyph))
{
x += desired_glyph->pixel_width;
++desired_glyph, ++current_glyph, ++i;
}
if (overlapping_glyphs_p
&& i > 0
&& i < current_row->used[TEXT_AREA]
&& (current_row->used[TEXT_AREA]
!= desired_row->used[TEXT_AREA]))
{
int left, right;
rif->get_glyph_overhangs (current_glyph, XFRAME (w->frame),
&left, &right);
while (left > 0 && i > 0)
{
--i, --desired_glyph, --current_glyph;
x -= desired_glyph->pixel_width;
left -= desired_glyph->pixel_width;
}
}
}
if (i < desired_row->used[TEXT_AREA])
{
int start_x = x, start_hpos = i;
struct glyph *start = desired_glyph;
int current_x = x;
int skip_first_p = !can_skip_p;
while (i < stop
&& (skip_first_p
|| !GLYPH_EQUAL_P (desired_glyph, current_glyph))
&& x == current_x)
{
x += desired_glyph->pixel_width;
current_x += current_glyph->pixel_width;
++desired_glyph, ++current_glyph, ++i;
skip_first_p = 0;
}
if (i == start_hpos || x != current_x)
{
i = start_hpos;
x = start_x;
desired_glyph = start;
break;
}
rif->cursor_to (vpos, start_hpos, desired_row->y, start_x);
rif->write_glyphs (start, i - start_hpos);
changed_p = 1;
}
}
if (i < desired_row->used[TEXT_AREA])
{
rif->cursor_to (vpos, i, desired_row->y, x);
rif->write_glyphs (desired_glyph, desired_row->used[TEXT_AREA] - i);
changed_p = 1;
}
if (MATRIX_ROW_EXTENDS_FACE_P (desired_row))
{
xassert (i < desired_row->used[TEXT_AREA]
|| ((desired_row->used[TEXT_AREA]
== current_row->used[TEXT_AREA])
&& MATRIX_ROW_EXTENDS_FACE_P (current_row)));
}
else if (MATRIX_ROW_EXTENDS_FACE_P (current_row))
{
if (i >= desired_row->used[TEXT_AREA])
rif->cursor_to (vpos, i, desired_row->y,
desired_row->pixel_width);
rif->clear_end_of_line (-1);
changed_p = 1;
}
else if (desired_row->pixel_width < current_row->pixel_width)
{
int x;
if (i >= desired_row->used[TEXT_AREA])
rif->cursor_to (vpos, i, desired_row->y,
desired_row->pixel_width);
if (vpos == w->phys_cursor.vpos
&& w->phys_cursor.hpos >= desired_row->used[TEXT_AREA])
{
w->phys_cursor_on_p = 0;
x = -1;
}
else
x = current_row->pixel_width;
rif->clear_end_of_line (x);
changed_p = 1;
}
}
return changed_p;
}
static int
update_window_line (w, vpos, mouse_face_overwritten_p)
struct window *w;
int vpos, *mouse_face_overwritten_p;
{
struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, vpos);
struct glyph_row *desired_row = MATRIX_ROW (w->desired_matrix, vpos);
int changed_p = 0;
updated_row = desired_row;
if (desired_row->mode_line_p
|| desired_row->visible_height > 0)
{
xassert (desired_row->enabled_p);
if (!desired_row->full_width_p
&& !NILP (w->left_margin_cols))
{
changed_p = 1;
update_marginal_area (w, LEFT_MARGIN_AREA, vpos);
}
if (update_text_area (w, vpos))
{
changed_p = 1;
if (current_row->mouse_face_p)
*mouse_face_overwritten_p = 1;
}
if (!desired_row->full_width_p
&& !NILP (w->right_margin_cols))
{
changed_p = 1;
update_marginal_area (w, RIGHT_MARGIN_AREA, vpos);
}
if (!current_row->enabled_p
|| desired_row->y != current_row->y
|| desired_row->visible_height != current_row->visible_height
|| desired_row->cursor_in_fringe_p != current_row->cursor_in_fringe_p
|| desired_row->overlay_arrow_bitmap != current_row->overlay_arrow_bitmap
|| current_row->redraw_fringe_bitmaps_p
|| desired_row->mode_line_p != current_row->mode_line_p
|| desired_row->exact_window_width_line_p != current_row->exact_window_width_line_p
|| (MATRIX_ROW_CONTINUATION_LINE_P (desired_row)
!= MATRIX_ROW_CONTINUATION_LINE_P (current_row)))
rif->after_update_window_line_hook (desired_row);
}
make_current (w->desired_matrix, w->current_matrix, vpos);
updated_row = NULL;
return changed_p;
}
static void
set_window_cursor_after_update (w)
struct window *w;
{
struct frame *f = XFRAME (w->frame);
int cx, cy, vpos, hpos;
xassert (FRAME_WINDOW_P (f));
if (cursor_in_echo_area
&& !NILP (echo_area_buffer[0])
&& XWINDOW (minibuf_window) == w
&& EQ (minibuf_window, echo_area_window)
&& FRAME_HAS_MINIBUF_P (f)
&& EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
{
cx = cy = vpos = hpos = 0;
if (cursor_in_echo_area >= 0)
{
struct glyph_row *row, *last_row;
struct glyph *glyph;
int yb = window_text_bottom_y (w);
last_row = NULL;
row = w->current_matrix->rows;
while (row->enabled_p
&& (last_row == NULL
|| MATRIX_ROW_BOTTOM_Y (row) <= yb))
{
if (row->used[TEXT_AREA]
&& row->glyphs[TEXT_AREA][0].charpos >= 0)
last_row = row;
++row;
}
if (last_row)
{
struct glyph *start = last_row->glyphs[TEXT_AREA];
struct glyph *last = start + last_row->used[TEXT_AREA] - 1;
while (last > start && last->charpos < 0)
--last;
for (glyph = start; glyph < last; ++glyph)
{
cx += glyph->pixel_width;
++hpos;
}
cy = last_row->y;
vpos = MATRIX_ROW_VPOS (last_row, w->current_matrix);
}
}
}
else
{
cx = w->cursor.x;
cy = w->cursor.y;
hpos = w->cursor.hpos;
vpos = w->cursor.vpos;
}
hpos = max (0, hpos);
hpos = min (w->current_matrix->matrix_w - 1, hpos);
vpos = max (0, vpos);
vpos = min (w->current_matrix->nrows - 1, vpos);
rif->cursor_to (vpos, hpos, cy, cx);
}
void
set_window_update_flags (w, on_p)
struct window *w;
int on_p;
{
while (w)
{
if (!NILP (w->hchild))
set_window_update_flags (XWINDOW (w->hchild), on_p);
else if (!NILP (w->vchild))
set_window_update_flags (XWINDOW (w->vchild), on_p);
else
w->must_be_updated_p = on_p;
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
}
struct row_entry
{
int old_uses, new_uses;
int new_line_number;
int bucket;
struct glyph_row *row;
struct row_entry *next;
};
static struct row_entry *row_entry_pool;
static int row_entry_pool_size;
static int row_entry_idx;
static struct row_entry **row_table;
static int row_table_size;
static struct row_entry **old_lines, **new_lines;
static int old_lines_size, new_lines_size;
static struct run *run_pool;
static int runs_size;
static struct run **runs;
static INLINE struct row_entry *
add_row_entry (w, row)
struct window *w;
struct glyph_row *row;
{
struct row_entry *entry;
int i = row->hash % row_table_size;
entry = row_table[i];
while (entry && !row_equal_p (w, entry->row, row, 1))
entry = entry->next;
if (entry == NULL)
{
entry = row_entry_pool + row_entry_idx++;
entry->row = row;
entry->old_uses = entry->new_uses = 0;
entry->new_line_number = 0;
entry->bucket = i;
entry->next = row_table[i];
row_table[i] = entry;
}
return entry;
}
static int
scrolling_window (w, header_line_p)
struct window *w;
int header_line_p;
{
struct glyph_matrix *desired_matrix = w->desired_matrix;
struct glyph_matrix *current_matrix = w->current_matrix;
int yb = window_text_bottom_y (w);
int i, j, first_old, first_new, last_old, last_new;
int nruns, nbytes, n, run_idx;
struct row_entry *entry;
for (i = header_line_p ? 1 : 0; i < current_matrix->nrows - 1; ++i)
{
struct glyph_row *d = MATRIX_ROW (desired_matrix, i);
struct glyph_row *c = MATRIX_ROW (current_matrix, i);
if (c->enabled_p
&& d->enabled_p
&& !d->redraw_fringe_bitmaps_p
&& c->y == d->y
&& MATRIX_ROW_BOTTOM_Y (c) <= yb
&& MATRIX_ROW_BOTTOM_Y (d) <= yb
&& row_equal_p (w, c, d, 1))
{
assign_row (c, d);
d->enabled_p = 0;
}
else
break;
}
if (!MATRIX_ROW (desired_matrix, i)->enabled_p)
return -1;
first_old = first_new = i;
i = first_new + 1;
while (i < desired_matrix->nrows - 1
&& MATRIX_ROW (desired_matrix, i)->enabled_p
&& MATRIX_ROW_BOTTOM_Y (MATRIX_ROW (desired_matrix, i)) <= yb)
++i;
if (!MATRIX_ROW (desired_matrix, i)->enabled_p)
return 0;
last_new = i;
i = first_old + 1;
while (i < current_matrix->nrows - 1)
{
int bottom = MATRIX_ROW_BOTTOM_Y (MATRIX_ROW (current_matrix, i));
if (bottom <= yb)
++i;
if (bottom >= yb)
break;
}
last_old = i;
i = last_new;
j = last_old;
while (i - 1 > first_new
&& j - 1 > first_old
&& MATRIX_ROW (current_matrix, i - 1)->enabled_p
&& (MATRIX_ROW (current_matrix, i - 1)->y
== MATRIX_ROW (desired_matrix, j - 1)->y)
&& !MATRIX_ROW (desired_matrix, j - 1)->redraw_fringe_bitmaps_p
&& row_equal_p (w,
MATRIX_ROW (desired_matrix, i - 1),
MATRIX_ROW (current_matrix, j - 1), 1))
--i, --j;
last_new = i;
last_old = j;
if (last_new == first_new)
return 0;
if (current_matrix->nrows > old_lines_size)
{
old_lines_size = current_matrix->nrows;
nbytes = old_lines_size * sizeof *old_lines;
old_lines = (struct row_entry **) xrealloc (old_lines, nbytes);
}
if (desired_matrix->nrows > new_lines_size)
{
new_lines_size = desired_matrix->nrows;
nbytes = new_lines_size * sizeof *new_lines;
new_lines = (struct row_entry **) xrealloc (new_lines, nbytes);
}
n = desired_matrix->nrows + current_matrix->nrows;
if (3 * n > row_table_size)
{
row_table_size = next_almost_prime (3 * n);
nbytes = row_table_size * sizeof *row_table;
row_table = (struct row_entry **) xrealloc (row_table, nbytes);
bzero (row_table, nbytes);
}
if (n > row_entry_pool_size)
{
row_entry_pool_size = n;
nbytes = row_entry_pool_size * sizeof *row_entry_pool;
row_entry_pool = (struct row_entry *) xrealloc (row_entry_pool, nbytes);
}
if (desired_matrix->nrows > runs_size)
{
runs_size = desired_matrix->nrows;
nbytes = runs_size * sizeof *runs;
runs = (struct run **) xrealloc (runs, nbytes);
nbytes = runs_size * sizeof *run_pool;
run_pool = (struct run *) xrealloc (run_pool, nbytes);
}
nruns = run_idx = 0;
row_entry_idx = 0;
for (i = first_old; i < last_old; ++i)
{
if (MATRIX_ROW (current_matrix, i)->enabled_p)
{
entry = add_row_entry (w, MATRIX_ROW (current_matrix, i));
old_lines[i] = entry;
++entry->old_uses;
}
else
old_lines[i] = NULL;
}
for (i = first_new; i < last_new; ++i)
{
xassert (MATRIX_ROW_ENABLED_P (desired_matrix, i));
entry = add_row_entry (w, MATRIX_ROW (desired_matrix, i));
++entry->new_uses;
entry->new_line_number = i;
new_lines[i] = entry;
}
for (i = first_old; i < last_old;)
if (old_lines[i]
&& old_lines[i]->old_uses == 1
&& old_lines[i]->new_uses == 1)
{
int j, k;
int new_line = old_lines[i]->new_line_number;
struct run *run = run_pool + run_idx++;
run->current_vpos = i;
run->current_y = MATRIX_ROW (current_matrix, i)->y;
run->desired_vpos = new_line;
run->desired_y = MATRIX_ROW (desired_matrix, new_line)->y;
run->nrows = 1;
run->height = MATRIX_ROW (current_matrix, i)->height;
j = i - 1;
k = new_line - 1;
while (j > first_old
&& k > first_new
&& old_lines[j] == new_lines[k])
{
int h = MATRIX_ROW (current_matrix, j)->height;
--run->current_vpos;
--run->desired_vpos;
++run->nrows;
run->height += h;
run->desired_y -= h;
run->current_y -= h;
--j, --k;
}
j = i + 1;
k = new_line + 1;
while (j < last_old
&& k < last_new
&& old_lines[j] == new_lines[k])
{
int h = MATRIX_ROW (current_matrix, j)->height;
++run->nrows;
run->height += h;
++j, ++k;
}
for (j = 0; j < nruns && runs[j]->height > run->height; ++j)
;
for (k = nruns; k > j; --k)
runs[k] = runs[k - 1];
runs[j] = run;
++nruns;
i += run->nrows;
}
else
++i;
for (i = 0; i < nruns; ++i)
if (runs[i]->nrows > 0)
{
struct run *r = runs[i];
if (r->current_y != r->desired_y)
{
rif->scroll_run_hook (w, r);
for (j = i + 1; j < nruns; ++j)
{
struct run *p = runs[j];
if ((p->current_y >= r->desired_y
&& p->current_y < r->desired_y + r->height)
|| (p->current_y + p->height >= r->desired_y
&& (p->current_y + p->height
< r->desired_y + r->height)))
p->nrows = 0;
}
}
for (j = 0; j < r->nrows; ++j)
{
struct glyph_row *from, *to;
int to_overlapped_p;
to = MATRIX_ROW (current_matrix, r->desired_vpos + j);
from = MATRIX_ROW (desired_matrix, r->desired_vpos + j);
to_overlapped_p = to->overlapped_p;
if (!from->mode_line_p && !w->pseudo_window_p
&& (to->left_fringe_bitmap != from->left_fringe_bitmap
|| to->right_fringe_bitmap != from->right_fringe_bitmap
|| to->left_fringe_face_id != from->left_fringe_face_id
|| to->right_fringe_face_id != from->right_fringe_face_id
|| to->overlay_arrow_bitmap != from->overlay_arrow_bitmap))
from->redraw_fringe_bitmaps_p = 1;
assign_row (to, from);
to->enabled_p = 1, from->enabled_p = 0;
to->overlapped_p = to_overlapped_p;
}
}
for (i = 0; i < row_entry_idx; ++i)
row_table[row_entry_pool[i].bucket] = NULL;
return nruns;
}
static int
update_frame_1 (f, force_p, inhibit_id_p)
struct frame *f;
int force_p;
int inhibit_id_p;
{
struct glyph_matrix *current_matrix = f->current_matrix;
struct glyph_matrix *desired_matrix = f->desired_matrix;
int i;
int pause;
int preempt_count = baud_rate / 2400 + 1;
extern int input_pending;
xassert (current_matrix && desired_matrix);
if (baud_rate != FRAME_COST_BAUD_RATE (f))
calculate_costs (f);
if (preempt_count <= 0)
preempt_count = 1;
#if !PERIODIC_PREEMPTION_CHECKING
if (!force_p && detect_input_pending_ignore_squeezables ())
{
pause = 1;
goto do_pause;
}
#endif
if (!line_ins_del_ok)
inhibit_id_p = 1;
for (i = 0; i < desired_matrix->nrows; i++)
if (MATRIX_ROW_ENABLED_P (desired_matrix, i))
break;
if (!inhibit_id_p && i < desired_matrix->nrows)
force_p |= scrolling (f);
if (MATRIX_ROW_ENABLED_P (desired_matrix, desired_matrix->nrows - 1))
update_frame_line (f, desired_matrix->nrows - 1);
for (i = 0; i < desired_matrix->nrows - 1 && (force_p || !input_pending); i++)
{
if (MATRIX_ROW_ENABLED_P (desired_matrix, i))
{
if (FRAME_TERMCAP_P (f))
{
int outq = PENDING_OUTPUT_COUNT (stdout);
if (outq > 900
|| (outq > 20 && ((i - 1) % preempt_count == 0)))
{
fflush (stdout);
if (preempt_count == 1)
{
#ifdef EMACS_OUTQSIZE
if (EMACS_OUTQSIZE (0, &outq) < 0)
outq = PENDING_OUTPUT_COUNT (stdout);
#endif
outq *= 10;
if (baud_rate <= outq && baud_rate > 0)
sleep (outq / baud_rate);
}
}
}
#if PERIODIC_PREEMPTION_CHECKING
if (!force_p)
{
EMACS_TIME tm, dif;
EMACS_GET_TIME (tm);
EMACS_SUB_TIME (dif, preemption_next_check, tm);
if (EMACS_TIME_NEG_P (dif))
{
EMACS_ADD_TIME (preemption_next_check, tm, preemption_period);
if (detect_input_pending_ignore_squeezables ())
break;
}
}
#else
if (!force_p && (i - 1) % preempt_count == 0)
detect_input_pending_ignore_squeezables ();
#endif
update_frame_line (f, i);
}
}
pause = (i < FRAME_LINES (f) - 1) ? i : 0;
if (!pause)
{
if ((cursor_in_echo_area
|| (EQ (minibuf_window, selected_window)
&& EQ (minibuf_window, echo_area_window)
&& !NILP (echo_area_buffer[0])))
&& FRAME_HAS_MINIBUF_P (f)
&& EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
{
int top = WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f)));
int row, col;
if (cursor_in_echo_area < 0)
{
row = top;
col = 0;
}
else
{
row = FRAME_LINES (f);
do
{
--row;
col = 0;
if (MATRIX_ROW_ENABLED_P (current_matrix, row))
{
struct glyph_row *r = MATRIX_ROW (current_matrix,
row);
struct glyph *start = r->glyphs[TEXT_AREA];
struct glyph *last = start + r->used[TEXT_AREA];
while (last > start
&& (last - 1)->charpos < 0)
--last;
col = last - start;
}
}
while (row > top && col == 0);
if (col >= FRAME_CURSOR_X_LIMIT (f))
{
if (row < FRAME_LINES (f) - 1)
{
col = FRAME_LEFT_SCROLL_BAR_COLS (f);
row++;
}
else
col = FRAME_CURSOR_X_LIMIT (f) - 1;
}
}
cursor_to (row, col);
}
else
{
struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
if (w->cursor.vpos >= 0
&& w->cursor.vpos < WINDOW_TOTAL_LINES (w))
{
int x = WINDOW_TO_FRAME_HPOS (w, w->cursor.hpos);
int y = WINDOW_TO_FRAME_VPOS (w, w->cursor.vpos);
if (INTEGERP (w->left_margin_cols))
x += XFASTINT (w->left_margin_cols);
cursor_to (y, x);
}
}
}
do_pause:
clear_desired_matrices (f);
return pause;
}
int
scrolling (frame)
struct frame *frame;
{
int unchanged_at_top, unchanged_at_bottom;
int window_size;
int changed_lines;
int *old_hash = (int *) alloca (FRAME_LINES (frame) * sizeof (int));
int *new_hash = (int *) alloca (FRAME_LINES (frame) * sizeof (int));
int *draw_cost = (int *) alloca (FRAME_LINES (frame) * sizeof (int));
int *old_draw_cost = (int *) alloca (FRAME_LINES (frame) * sizeof (int));
register int i;
int free_at_end_vpos = FRAME_LINES (frame);
struct glyph_matrix *current_matrix = frame->current_matrix;
struct glyph_matrix *desired_matrix = frame->desired_matrix;
if (!current_matrix)
abort ();
changed_lines = 0;
unchanged_at_top = 0;
unchanged_at_bottom = FRAME_LINES (frame);
for (i = 0; i < FRAME_LINES (frame); i++)
{
if (!MATRIX_ROW_ENABLED_P (current_matrix, i))
return 0;
old_hash[i] = line_hash_code (MATRIX_ROW (current_matrix, i));
if (! MATRIX_ROW_ENABLED_P (desired_matrix, i))
{
new_hash[i] = old_hash[i];
#define INFINITY 1000000
draw_cost[i] = INFINITY;
}
else
{
new_hash[i] = line_hash_code (MATRIX_ROW (desired_matrix, i));
draw_cost[i] = line_draw_cost (desired_matrix, i);
}
if (old_hash[i] != new_hash[i])
{
changed_lines++;
unchanged_at_bottom = FRAME_LINES (frame) - i - 1;
}
else if (i == unchanged_at_top)
unchanged_at_top++;
old_draw_cost[i] = line_draw_cost (current_matrix, i);
}
if ((!scroll_region_ok && changed_lines < baud_rate / 2400)
|| unchanged_at_bottom == FRAME_LINES (frame))
return 1;
window_size = (FRAME_LINES (frame) - unchanged_at_top
- unchanged_at_bottom);
if (scroll_region_ok)
free_at_end_vpos -= unchanged_at_bottom;
else if (memory_below_frame)
free_at_end_vpos = -1;
if (!scroll_region_ok && window_size >= 18 && baud_rate > 2400
&& (window_size >=
10 * scrolling_max_lines_saved (unchanged_at_top,
FRAME_LINES (frame) - unchanged_at_bottom,
old_hash, new_hash, draw_cost)))
return 0;
if (window_size < 2)
return 0;
scrolling_1 (frame, window_size, unchanged_at_top, unchanged_at_bottom,
draw_cost + unchanged_at_top - 1,
old_draw_cost + unchanged_at_top - 1,
old_hash + unchanged_at_top - 1,
new_hash + unchanged_at_top - 1,
free_at_end_vpos - unchanged_at_top);
return 0;
}
static int
count_blanks (r, len)
struct glyph *r;
int len;
{
int i;
for (i = 0; i < len; ++i)
if (!CHAR_GLYPH_SPACE_P (r[i]))
break;
return i;
}
static int
count_match (str1, end1, str2, end2)
struct glyph *str1, *end1, *str2, *end2;
{
struct glyph *p1 = str1;
struct glyph *p2 = str2;
while (p1 < end1
&& p2 < end2
&& GLYPH_CHAR_AND_FACE_EQUAL_P (p1, p2))
++p1, ++p2;
return p1 - str1;
}
extern int *char_ins_del_vector;
#define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_TOTAL_COLS((f))])
static void
update_frame_line (f, vpos)
struct frame *f;
int vpos;
{
struct glyph *obody, *nbody, *op1, *op2, *np1, *nend;
int tem;
int osp, nsp, begmatch, endmatch, olen, nlen;
struct glyph_matrix *current_matrix = f->current_matrix;
struct glyph_matrix *desired_matrix = f->desired_matrix;
struct glyph_row *current_row = MATRIX_ROW (current_matrix, vpos);
struct glyph_row *desired_row = MATRIX_ROW (desired_matrix, vpos);
int must_write_whole_line_p;
int write_spaces_p = must_write_spaces;
int colored_spaces_p = (FACE_FROM_ID (f, DEFAULT_FACE_ID)->background
!= FACE_TTY_DEFAULT_BG_COLOR);
if (colored_spaces_p)
write_spaces_p = 1;
must_write_whole_line_p = !current_row->enabled_p;
if (must_write_whole_line_p)
{
obody = 0;
olen = 0;
}
else
{
obody = MATRIX_ROW_GLYPH_START (current_matrix, vpos);
olen = current_row->used[TEXT_AREA];
if (!write_spaces_p)
while (olen > 0 && CHAR_GLYPH_SPACE_P (obody[olen-1]))
olen--;
}
current_row->enabled_p = 1;
current_row->used[TEXT_AREA] = desired_row->used[TEXT_AREA];
if (!desired_row->enabled_p)
{
nlen = 0;
goto just_erase;
}
nbody = desired_row->glyphs[TEXT_AREA];
nlen = desired_row->used[TEXT_AREA];
nend = nbody + nlen;
if (must_write_whole_line_p)
{
if (!write_spaces_p)
while (nlen > 0 && CHAR_GLYPH_SPACE_P (nbody[nlen - 1]))
--nlen;
if (nlen)
{
cursor_to (vpos, 0);
write_glyphs (nbody, nlen);
}
if (nlen < FRAME_TOTAL_COLS (f))
{
cursor_to (vpos, nlen);
clear_end_of_line (FRAME_TOTAL_COLS (f));
}
else
cursor_to (vpos, 0);
make_current (desired_matrix, current_matrix, vpos);
return;
}
if (!write_spaces_p)
while (nlen > 0 && CHAR_GLYPH_SPACE_P (nbody[nlen - 1]))
nlen--;
if (!char_ins_del_ok)
{
int i, j;
for (i = 0; i < nlen; i++)
{
if (i >= olen || !GLYPH_EQUAL_P (nbody + i, obody + i))
{
j = i + 1;
while (j < nlen
&& (j >= olen
|| !GLYPH_EQUAL_P (nbody + j, obody + j)
|| CHAR_GLYPH_PADDING_P (nbody[j])))
++j;
cursor_to (vpos, i);
write_glyphs (nbody + i, j - i);
i = j - 1;
}
}
if (olen > nlen)
{
cursor_to (vpos, nlen);
clear_end_of_line (olen);
}
make_current (desired_matrix, current_matrix, vpos);
return;
}
if (!olen)
{
if (write_spaces_p)
nsp = 0;
else
nsp = count_blanks (nbody, nlen);
if (nlen > nsp)
{
cursor_to (vpos, nsp);
write_glyphs (nbody + nsp, nlen - nsp);
}
make_current (desired_matrix, current_matrix, vpos);
return;
}
osp = count_blanks (obody, olen);
nsp = (colored_spaces_p ? 0 : count_blanks (nbody, nlen));
begmatch = count_match (obody + osp, obody + olen,
nbody + nsp, nbody + nlen);
if (!write_spaces_p && osp + begmatch == olen)
{
np1 = nbody + nsp;
while (np1 + begmatch < nend && CHAR_GLYPH_SPACE_P (np1[begmatch]))
++begmatch;
}
if (begmatch == 0 && osp != nsp)
osp = nsp = min (osp, nsp);
op1 = obody + olen;
np1 = nbody + nlen;
op2 = op1 + begmatch - min (olen - osp, nlen - nsp);
while (op1 > op2
&& GLYPH_EQUAL_P (op1 - 1, np1 - 1))
{
op1--;
np1--;
}
endmatch = obody + olen - op1;
tem = (nlen - nsp) - (olen - osp);
if (endmatch && tem
&& (!char_ins_del_ok || endmatch <= char_ins_del_cost (f)[tem]))
endmatch = 0;
if (nsp != osp
&& (!char_ins_del_ok
|| begmatch + endmatch <= char_ins_del_cost (f)[nsp - osp]))
{
begmatch = 0;
endmatch = 0;
osp = nsp = min (osp, nsp);
}
if (osp > nsp)
{
cursor_to (vpos, nsp);
delete_glyphs (osp - nsp);
}
else if (nsp > osp)
{
if (endmatch && nlen < olen + nsp - osp)
{
cursor_to (vpos, nlen - endmatch + osp - nsp);
delete_glyphs (olen + nsp - osp - nlen);
olen = nlen - (nsp - osp);
}
cursor_to (vpos, osp);
insert_glyphs (0, nsp - osp);
}
olen += nsp - osp;
tem = nsp + begmatch + endmatch;
if (nlen != tem || olen != tem)
{
if (!endmatch || nlen == olen)
{
if (nlen == FRAME_TOTAL_COLS (f))
olen = 0;
if (nlen - tem > 0)
{
cursor_to (vpos, nsp + begmatch);
write_glyphs (nbody + nsp + begmatch, nlen - tem);
}
}
else if (nlen > olen)
{
int out = olen - tem;
int del;
cursor_to (vpos, nsp + begmatch);
while (CHAR_GLYPH_PADDING_P (nbody[nsp + begmatch + out]))
out--;
write_glyphs (nbody + nsp + begmatch, out);
del = olen - tem - out;
if (del > 0)
delete_glyphs (del);
insert_glyphs (nbody + nsp + begmatch + out, nlen - olen + del);
olen = nlen;
}
else if (olen > nlen)
{
cursor_to (vpos, nsp + begmatch);
write_glyphs (nbody + nsp + begmatch, nlen - tem);
delete_glyphs (olen - nlen);
olen = nlen;
}
}
just_erase:
if (olen > nlen)
{
cursor_to (vpos, nlen);
clear_end_of_line (olen);
}
make_current (desired_matrix, current_matrix, vpos);
}
Lisp_Object
buffer_posn_from_coords (w, x, y, pos, object, dx, dy, width, height)
struct window *w;
int *x, *y;
struct display_pos *pos;
Lisp_Object *object;
int *dx, *dy;
int *width, *height;
{
struct it it;
struct buffer *old_current_buffer = current_buffer;
struct text_pos startp;
Lisp_Object string;
struct glyph_row *row;
#ifdef HAVE_WINDOW_SYSTEM
struct image *img = 0;
#endif
int x0, x1;
current_buffer = XBUFFER (w->buffer);
SET_TEXT_POS_FROM_MARKER (startp, w->start);
CHARPOS (startp) = min (ZV, max (BEGV, CHARPOS (startp)));
BYTEPOS (startp) = min (ZV_BYTE, max (BEGV_BYTE, BYTEPOS (startp)));
start_display (&it, w, startp);
x0 = *x - WINDOW_LEFT_MARGIN_WIDTH (w);
move_it_to (&it, -1, x0 + it.first_visible_x, *y, -1,
MOVE_TO_X | MOVE_TO_Y);
current_buffer = old_current_buffer;
*dx = x0 + it.first_visible_x - it.current_x;
*dy = *y - it.current_y;
string = w->buffer;
if (STRINGP (it.string))
string = it.string;
*pos = it.current;
#ifdef HAVE_WINDOW_SYSTEM
if (it.what == IT_IMAGE)
{
if ((img = IMAGE_FROM_ID (it.f, it.image_id)) != NULL
&& !NILP (img->spec))
*object = img->spec;
}
#endif
if (it.vpos < w->current_matrix->nrows
&& (row = MATRIX_ROW (w->current_matrix, it.vpos),
row->enabled_p))
{
if (it.hpos < row->used[TEXT_AREA])
{
struct glyph *glyph = row->glyphs[TEXT_AREA] + it.hpos;
#ifdef HAVE_WINDOW_SYSTEM
if (img)
{
*dy -= row->ascent - glyph->ascent;
*dx += glyph->slice.x;
*dy += glyph->slice.y;
*width = img->width;
*height = img->height;
}
else
#endif
{
*width = glyph->pixel_width;
*height = glyph->ascent + glyph->descent;
}
}
else
{
*width = 0;
*height = row->height;
}
}
else
{
*width = *height = 0;
}
x1 = max(0, it.current_x + it.pixel_width - it.first_visible_x);
if (x0 > x1)
it.hpos += (x0 - x1) / WINDOW_FRAME_COLUMN_WIDTH (w);
*x = it.hpos;
*y = it.vpos;
return string;
}
Lisp_Object
mode_line_string (w, part, x, y, charpos, object, dx, dy, width, height)
struct window *w;
enum window_part part;
int *x, *y;
int *charpos;
Lisp_Object *object;
int *dx, *dy;
int *width, *height;
{
struct glyph_row *row;
struct glyph *glyph, *end;
int x0, y0;
Lisp_Object string = Qnil;
if (part == ON_MODE_LINE)
row = MATRIX_MODE_LINE_ROW (w->current_matrix);
else
row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
y0 = *y - row->y;
*y = row - MATRIX_FIRST_TEXT_ROW (w->current_matrix);
if (row->mode_line_p && row->enabled_p)
{
glyph = row->glyphs[TEXT_AREA];
end = glyph + row->used[TEXT_AREA];
for (x0 = *x; glyph < end && x0 >= glyph->pixel_width; ++glyph)
x0 -= glyph->pixel_width;
*x = glyph - row->glyphs[TEXT_AREA];
if (glyph < end)
{
string = glyph->object;
*charpos = glyph->charpos;
*width = glyph->pixel_width;
*height = glyph->ascent + glyph->descent;
#ifdef HAVE_WINDOW_SYSTEM
if (glyph->type == IMAGE_GLYPH)
{
struct image *img;
img = IMAGE_FROM_ID (WINDOW_XFRAME (w), glyph->u.img_id);
if (img != NULL)
*object = img->spec;
y0 -= row->ascent - glyph->ascent;
}
#endif
}
else
{
*x += x0 / WINDOW_FRAME_COLUMN_WIDTH (w);
*width = 0;
*height = row->height;
}
}
else
{
*x = 0;
x0 = 0;
*width = *height = 0;
}
*dx = x0;
*dy = y0;
return string;
}
Lisp_Object
marginal_area_string (w, part, x, y, charpos, object, dx, dy, width, height)
struct window *w;
enum window_part part;
int *x, *y;
int *charpos;
Lisp_Object *object;
int *dx, *dy;
int *width, *height;
{
struct glyph_row *row = w->current_matrix->rows;
struct glyph *glyph, *end;
int x0, y0, i, wy = *y;
int area;
Lisp_Object string = Qnil;
if (part == ON_LEFT_MARGIN)
area = LEFT_MARGIN_AREA;
else if (part == ON_RIGHT_MARGIN)
area = RIGHT_MARGIN_AREA;
else
abort ();
for (i = 0; row->enabled_p && i < w->current_matrix->nrows; ++i, ++row)
if (wy >= row->y && wy < MATRIX_ROW_BOTTOM_Y (row))
break;
y0 = *y - row->y;
*y = row - MATRIX_FIRST_TEXT_ROW (w->current_matrix);
if (row->enabled_p)
{
if (area == RIGHT_MARGIN_AREA)
x0 = ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
? WINDOW_LEFT_FRINGE_WIDTH (w)
: WINDOW_TOTAL_FRINGE_WIDTH (w))
+ window_box_width (w, LEFT_MARGIN_AREA)
+ window_box_width (w, TEXT_AREA));
else
x0 = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
? WINDOW_LEFT_FRINGE_WIDTH (w)
: 0);
glyph = row->glyphs[area];
end = glyph + row->used[area];
for (x0 = *x - x0; glyph < end && x0 >= glyph->pixel_width; ++glyph)
x0 -= glyph->pixel_width;
*x = glyph - row->glyphs[area];
if (glyph < end)
{
string = glyph->object;
*charpos = glyph->charpos;
*width = glyph->pixel_width;
*height = glyph->ascent + glyph->descent;
#ifdef HAVE_WINDOW_SYSTEM
if (glyph->type == IMAGE_GLYPH)
{
struct image *img;
img = IMAGE_FROM_ID (WINDOW_XFRAME (w), glyph->u.img_id);
if (img != NULL)
*object = img->spec;
y0 -= row->ascent - glyph->ascent;
x0 += glyph->slice.x;
y0 += glyph->slice.y;
}
#endif
}
else
{
*x += x0 / WINDOW_FRAME_COLUMN_WIDTH (w);
*width = 0;
*height = row->height;
}
}
else
{
x0 = 0;
*x = 0;
*width = *height = 0;
}
*dx = x0;
*dy = y0;
return string;
}
#ifdef SIGWINCH
SIGTYPE
window_change_signal (signalnum)
int signalnum;
{
int width, height;
#ifndef USE_CRT_DLL
extern int errno;
#endif
int old_errno = errno;
signal (SIGWINCH, window_change_signal);
SIGNAL_THREAD_CHECK (signalnum);
get_frame_size (&width, &height);
{
Lisp_Object tail, frame;
FOR_EACH_FRAME (tail, frame)
{
if (FRAME_TERMCAP_P (XFRAME (frame)))
{
change_frame_size (XFRAME (frame), height, width, 0, 1, 0);
break;
}
}
}
errno = old_errno;
}
#endif
void
do_pending_window_change (safe)
int safe;
{
if (redisplaying_p && !safe)
return;
while (delayed_size_change)
{
Lisp_Object tail, frame;
delayed_size_change = 0;
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
if (f->new_text_lines != 0 || f->new_text_cols != 0)
change_frame_size (f, f->new_text_lines, f->new_text_cols,
0, 0, safe);
}
}
}
void
change_frame_size (f, newheight, newwidth, pretend, delay, safe)
register struct frame *f;
int newheight, newwidth, pretend, delay, safe;
{
Lisp_Object tail, frame;
if (! FRAME_WINDOW_P (f))
{
FOR_EACH_FRAME (tail, frame)
if (! FRAME_WINDOW_P (XFRAME (frame)))
change_frame_size_1 (XFRAME (frame), newheight, newwidth,
pretend, delay, safe);
}
else
change_frame_size_1 (f, newheight, newwidth, pretend, delay, safe);
}
static void
change_frame_size_1 (f, newheight, newwidth, pretend, delay, safe)
register struct frame *f;
int newheight, newwidth, pretend, delay, safe;
{
int new_frame_total_cols;
int count = SPECPDL_INDEX ();
if (delay || (redisplaying_p && !safe))
{
f->new_text_lines = newheight;
f->new_text_cols = newwidth;
delayed_size_change = 1;
return;
}
f->new_text_lines = 0;
f->new_text_cols = 0;
if (newheight == 0)
newheight = FRAME_LINES (f);
if (newwidth == 0)
newwidth = FRAME_COLS (f);
new_frame_total_cols = FRAME_TOTAL_COLS_ARG (f, newwidth);
check_frame_size (f, &newheight, &newwidth);
if (newheight == FRAME_LINES (f)
&& new_frame_total_cols == FRAME_TOTAL_COLS (f))
return;
BLOCK_INPUT;
#ifdef MSDOS
dos_set_window_size (&newheight, &newwidth);
#endif
if (newheight != FRAME_LINES (f))
{
if (FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
{
XSETFASTINT (XWINDOW (FRAME_ROOT_WINDOW (f))->top_line,
FRAME_TOP_MARGIN (f));
set_window_height (FRAME_ROOT_WINDOW (f),
(newheight
- 1
- FRAME_TOP_MARGIN (f)),
0);
XSETFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top_line,
newheight - 1);
set_window_height (FRAME_MINIBUF_WINDOW (f), 1, 0);
}
else
set_window_height (FRAME_ROOT_WINDOW (f),
newheight - FRAME_TOP_MARGIN (f), 0);
if (FRAME_TERMCAP_P (f) && !pretend)
FrameRows = newheight;
}
if (new_frame_total_cols != FRAME_TOTAL_COLS (f))
{
set_window_width (FRAME_ROOT_WINDOW (f), new_frame_total_cols, 0);
if (FRAME_HAS_MINIBUF_P (f))
set_window_width (FRAME_MINIBUF_WINDOW (f), new_frame_total_cols, 0);
if (FRAME_TERMCAP_P (f) && !pretend)
FrameCols = newwidth;
if (WINDOWP (f->tool_bar_window))
XSETFASTINT (XWINDOW (f->tool_bar_window)->total_cols, newwidth);
}
FRAME_LINES (f) = newheight;
SET_FRAME_COLS (f, newwidth);
{
struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
int text_area_x, text_area_y, text_area_width, text_area_height;
window_box (w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width,
&text_area_height);
if (w->cursor.x >= text_area_x + text_area_width)
w->cursor.hpos = w->cursor.x = 0;
if (w->cursor.y >= text_area_y + text_area_height)
w->cursor.vpos = w->cursor.y = 0;
}
adjust_glyphs (f);
calculate_costs (f);
SET_FRAME_GARBAGED (f);
f->resized_p = 1;
UNBLOCK_INPUT;
record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
Fset_window_buffer (FRAME_SELECTED_WINDOW (f),
XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer, Qt);
unbind_to (count, Qnil);
}
DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript,
1, 1, "FOpen termscript file: ",
doc: )
(file)
Lisp_Object file;
{
if (termscript != 0)
{
BLOCK_INPUT;
fclose (termscript);
UNBLOCK_INPUT;
}
termscript = 0;
if (! NILP (file))
{
file = Fexpand_file_name (file, Qnil);
termscript = fopen (SDATA (file), "w");
if (termscript == 0)
report_file_error ("Opening termscript", Fcons (file, Qnil));
}
return Qnil;
}
DEFUN ("send-string-to-terminal", Fsend_string_to_terminal,
Ssend_string_to_terminal, 1, 1, 0,
doc: )
(string)
Lisp_Object string;
{
CHECK_STRING (string);
BLOCK_INPUT;
fwrite (SDATA (string), 1, SBYTES (string), stdout);
fflush (stdout);
if (termscript)
{
fwrite (SDATA (string), 1, SBYTES (string),
termscript);
fflush (termscript);
}
UNBLOCK_INPUT;
return Qnil;
}
DEFUN ("ding", Fding, Sding, 0, 1, 0,
doc: )
(arg)
Lisp_Object arg;
{
if (!NILP (arg))
{
if (noninteractive)
putchar (07);
else
ring_bell ();
fflush (stdout);
}
else
bitch_at_user ();
return Qnil;
}
void
bitch_at_user ()
{
if (noninteractive)
putchar (07);
else if (!INTERACTIVE)
error ("Keyboard macro terminated by a command ringing the bell");
else
ring_bell ();
fflush (stdout);
}
DEFUN ("sleep-for", Fsleep_for, Ssleep_for, 1, 2, 0,
doc: )
(seconds, milliseconds)
Lisp_Object seconds, milliseconds;
{
int sec, usec;
if (NILP (milliseconds))
XSETINT (milliseconds, 0);
else
CHECK_NUMBER (milliseconds);
usec = XINT (milliseconds) * 1000;
{
double duration = extract_float (seconds);
sec = (int) duration;
usec += (duration - sec) * 1000000;
}
#ifndef EMACS_HAS_USECS
if (sec == 0 && usec != 0)
error ("Millisecond `sleep-for' not supported on %s", SYSTEM_TYPE);
#endif
if (usec < 0)
{
if (-1000000 < usec)
sec--, usec += 1000000;
else
sec -= -usec / 1000000, usec = 1000000 - (-usec % 1000000);
}
else
sec += usec / 1000000, usec %= 1000000;
if (sec < 0 || (sec == 0 && usec == 0))
return Qnil;
wait_reading_process_output (sec, usec, 0, 0, Qnil, NULL, 0);
return Qnil;
}
Lisp_Object
sit_for (timeout, reading, do_display)
Lisp_Object timeout;
int reading, do_display;
{
int sec, usec;
swallow_events (do_display);
if ((detect_input_pending_run_timers (do_display))
|| !NILP (Vexecuting_kbd_macro))
return Qnil;
if (do_display >= 2)
redisplay_preserve_echo_area (2);
if (INTEGERP (timeout))
{
sec = XINT (timeout);
usec = 0;
}
else if (FLOATP (timeout))
{
double seconds = XFLOAT_DATA (timeout);
sec = (int) seconds;
usec = (int) ((seconds - sec) * 1000000);
}
else if (EQ (timeout, Qt))
{
sec = 0;
usec = 0;
}
else
wrong_type_argument (Qnumberp, timeout);
if (sec == 0 && usec == 0 && !EQ (timeout, Qt))
return Qt;
#ifdef SIGIO
gobble_input (0);
#endif
wait_reading_process_output (sec, usec, reading ? -1 : 1, do_display,
Qnil, NULL, 0);
return detect_input_pending () ? Qnil : Qt;
}
DEFUN ("redisplay", Fredisplay, Sredisplay, 0, 1, 0,
doc: )
(force)
Lisp_Object force;
{
int count;
swallow_events (1);
if ((detect_input_pending_run_timers (1)
&& NILP (force) && !redisplay_dont_pause)
|| !NILP (Vexecuting_kbd_macro))
return Qnil;
count = SPECPDL_INDEX ();
if (!NILP (force) && !redisplay_dont_pause)
specbind (Qredisplay_dont_pause, Qt);
redisplay_preserve_echo_area (2);
unbind_to (count, Qnil);
return Qt;
}
static Lisp_Object frame_and_buffer_state;
DEFUN ("frame-or-buffer-changed-p", Fframe_or_buffer_changed_p,
Sframe_or_buffer_changed_p, 0, 1, 0,
doc: )
(variable)
Lisp_Object variable;
{
Lisp_Object state, tail, frame, buf;
Lisp_Object *vecp, *end;
int n;
if (! NILP (variable))
{
CHECK_SYMBOL (variable);
state = Fsymbol_value (variable);
if (! VECTORP (state))
goto changed;
}
else
state = frame_and_buffer_state;
vecp = XVECTOR (state)->contents;
end = vecp + XVECTOR (state)->size;
FOR_EACH_FRAME (tail, frame)
{
if (vecp == end)
goto changed;
if (!EQ (*vecp++, frame))
goto changed;
if (vecp == end)
goto changed;
if (!EQ (*vecp++, XFRAME (frame)->name))
goto changed;
}
for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail))
{
buf = XCDR (XCAR (tail));
if (SREF (XBUFFER (buf)->name, 0) == ' ')
continue;
if (vecp == end)
goto changed;
if (!EQ (*vecp++, buf))
goto changed;
if (vecp == end)
goto changed;
if (!EQ (*vecp++, XBUFFER (buf)->read_only))
goto changed;
if (vecp == end)
goto changed;
if (!EQ (*vecp++, Fbuffer_modified_p (buf)))
goto changed;
}
if (vecp == end)
goto changed;
if (EQ (*vecp, Qlambda))
return Qnil;
changed:
n = 1;
FOR_EACH_FRAME (tail, frame)
n += 2;
for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail))
n += 3;
if (! VECTORP (state)
|| n > XVECTOR (state)->size
|| n + 20 < XVECTOR (state)->size / 2)
{
state = Fmake_vector (make_number (n + 20), Qlambda);
if (! NILP (variable))
Fset (variable, state);
else
frame_and_buffer_state = state;
}
vecp = XVECTOR (state)->contents;
FOR_EACH_FRAME (tail, frame)
{
*vecp++ = frame;
*vecp++ = XFRAME (frame)->name;
}
for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail))
{
buf = XCDR (XCAR (tail));
if (SREF (XBUFFER (buf)->name, 0) == ' ')
continue;
*vecp++ = buf;
*vecp++ = XBUFFER (buf)->read_only;
*vecp++ = Fbuffer_modified_p (buf);
}
*vecp++ = Qlambda;
while (vecp - XVECTOR (state)->contents
< XVECTOR (state)->size)
*vecp++ = Qlambda;
if (vecp - XVECTOR (state)->contents
> XVECTOR (state)->size)
abort ();
return Qt;
}
char *terminal_type;
void
init_display ()
{
#ifdef HAVE_X_WINDOWS
extern int display_arg;
#endif
space_glyph.type = CHAR_GLYPH;
SET_CHAR_GLYPH_FROM_GLYPH (space_glyph, ' ');
space_glyph.charpos = -1;
meta_key = 0;
inverse_video = 0;
cursor_in_echo_area = 0;
terminal_type = (char *) 0;
Vwindow_system = Qnil;
#ifdef HAVE_X_WINDOWS
if (! inhibit_window_system && ! display_arg)
{
char *display;
#ifdef VMS
display = getenv ("DECW$DISPLAY");
#else
display = getenv ("DISPLAY");
#endif
display_arg = (display != 0 && *display != 0);
if (display_arg && !x_display_ok (display))
{
fprintf (stderr, "Display %s unavailable, simulating -nw\n",
display);
inhibit_window_system = 1;
}
}
if (!inhibit_window_system && display_arg
#ifndef CANNOT_DUMP
&& initialized
#endif
)
{
Vwindow_system = intern ("x");
#ifdef HAVE_X11
Vwindow_system_version = make_number (11);
#else
Vwindow_system_version = make_number (10);
#endif
#if defined (GNU_LINUX) && defined (HAVE_LIBNCURSES)
{ char b[2044]; tgetent (b, "xterm");}
#endif
adjust_frame_glyphs_initially ();
return;
}
#endif
#ifdef HAVE_NTGUI
if (!inhibit_window_system)
{
Vwindow_system = intern ("w32");
Vwindow_system_version = make_number (1);
adjust_frame_glyphs_initially ();
return;
}
#endif
#ifdef MAC_OS
if (!inhibit_window_system && !isatty(0))
{
Vwindow_system = intern ("mac");
Vwindow_system_version = make_number (1);
adjust_frame_glyphs_initially ();
return;
}
#endif
if (! isatty (0))
{
fatal ("standard input is not a tty");
exit (1);
}
terminal_type = (char *) getenv ("TERM");
if (!terminal_type)
{
#ifdef VMS
fprintf (stderr, "Please specify your terminal type.\n\
For types defined in VMS, use set term /device=TYPE.\n\
For types not defined in VMS, use define emacs_term \"TYPE\".\n\
\(The quotation marks are necessary since terminal types are lower case.)\n");
#else
#ifdef HAVE_WINDOW_SYSTEM
if (! inhibit_window_system)
fprintf (stderr, "Please set the environment variable DISPLAY or TERM (see `tset').\n");
else
#endif
fprintf (stderr, "Please set the environment variable TERM; see `tset'.\n");
#endif
exit (1);
}
#ifdef VMS
{
char *new = (char *) xmalloc (strlen (terminal_type) + 1);
char *p;
strcpy (new, terminal_type);
for (p = new; *p; p++)
if (isupper (*p))
*p = tolower (*p);
terminal_type = new;
}
#endif
term_init (terminal_type);
{
struct frame *sf = SELECTED_FRAME ();
int width = FRAME_TOTAL_COLS (sf);
int height = FRAME_LINES (sf);
unsigned int total_glyphs = height * (width + 2) * sizeof (struct glyph);
if (total_glyphs / sizeof (struct glyph) / height != width + 2)
fatal ("screen size %dx%d too big", width, height);
}
adjust_frame_glyphs_initially ();
calculate_costs (XFRAME (selected_frame));
#ifdef SIGWINCH
#ifndef CANNOT_DUMP
if (initialized)
#endif
signal (SIGWINCH, window_change_signal);
#endif
if (initialized
&& !noninteractive
#ifdef MSDOS
&& (strcmp (terminal_type, "internal") != 0 || inhibit_window_system)
#endif
&& NILP (Vwindow_system))
{
struct frame *sf = SELECTED_FRAME();
FRAME_FOREGROUND_PIXEL (sf) = FACE_TTY_DEFAULT_FG_COLOR;
FRAME_BACKGROUND_PIXEL (sf) = FACE_TTY_DEFAULT_BG_COLOR;
call0 (intern ("tty-set-up-initial-frame-faces"));
}
}
DEFUN ("internal-show-cursor", Finternal_show_cursor,
Sinternal_show_cursor, 2, 2, 0,
doc: )
(window, show)
Lisp_Object window, show;
{
if (!redisplaying_p)
{
if (NILP (window))
window = selected_window;
else
CHECK_WINDOW (window);
XWINDOW (window)->cursor_off_p = NILP (show);
}
return Qnil;
}
DEFUN ("internal-show-cursor-p", Finternal_show_cursor_p,
Sinternal_show_cursor_p, 0, 1, 0,
doc: )
(window)
Lisp_Object window;
{
struct window *w;
if (NILP (window))
window = selected_window;
else
CHECK_WINDOW (window);
w = XWINDOW (window);
return w->cursor_off_p ? Qnil : Qt;
}
void
syms_of_display ()
{
defsubr (&Sredraw_frame);
defsubr (&Sredraw_display);
defsubr (&Sframe_or_buffer_changed_p);
defsubr (&Sopen_termscript);
defsubr (&Sding);
defsubr (&Sredisplay);
defsubr (&Ssleep_for);
defsubr (&Ssend_string_to_terminal);
defsubr (&Sinternal_show_cursor);
defsubr (&Sinternal_show_cursor_p);
#if GLYPH_DEBUG
defsubr (&Sdump_redisplay_history);
#endif
frame_and_buffer_state = Fmake_vector (make_number (20), Qlambda);
staticpro (&frame_and_buffer_state);
Qdisplay_table = intern ("display-table");
staticpro (&Qdisplay_table);
Qredisplay_dont_pause = intern ("redisplay-dont-pause");
staticpro (&Qredisplay_dont_pause);
DEFVAR_INT ("baud-rate", &baud_rate,
doc: );
DEFVAR_BOOL ("inverse-video", &inverse_video,
doc: );
DEFVAR_BOOL ("visible-bell", &visible_bell,
doc: );
DEFVAR_BOOL ("no-redraw-on-reenter", &no_redraw_on_reenter,
doc: );
DEFVAR_LISP ("window-system", &Vwindow_system,
doc: );
DEFVAR_LISP ("window-system-version", &Vwindow_system_version,
doc: );
DEFVAR_BOOL ("cursor-in-echo-area", &cursor_in_echo_area,
doc: );
DEFVAR_LISP ("glyph-table", &Vglyph_table,
doc: );
Vglyph_table = Qnil;
DEFVAR_LISP ("standard-display-table", &Vstandard_display_table,
doc: );
Vstandard_display_table = Qnil;
DEFVAR_BOOL ("redisplay-dont-pause", &redisplay_dont_pause,
doc: );
redisplay_dont_pause = 0;
#if PERIODIC_PREEMPTION_CHECKING
DEFVAR_LISP ("redisplay-preemption-period", &Vredisplay_preemption_period,
doc: );
Vredisplay_preemption_period = make_float (0.10);
#endif
#ifdef CANNOT_DUMP
if (noninteractive)
#endif
{
Vwindow_system = Qnil;
Vwindow_system_version = Qnil;
}
}