#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 macintosh
#include "macterm.h"
#endif
#include "systime.h"
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#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 (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 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;
int frame_garbaged;
int display_completed;
int visible_bell;
int inverse_video;
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 *) XSTRING (XBUFFER (w->buffer)->name)->data
: "???"),
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, "",
"Dump redisplay history to stderr.")
()
{
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) + XFASTINT ((W)->top))
#define WINDOW_TO_FRAME_HPOS(W, HPOS) ((HPOS) + XFASTINT ((W)->left))
#endif
void
safe_bcopy (from, to, size)
char *from, *to;
int size;
{
if (size <= 0 || from == to)
return;
if (to < from || from + size <= to)
bcopy (from, to, size);
else
{
register 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->width);
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_x, window_y, window_width = -1, window_height;
if (w)
{
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)
{
window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
left = margin_glyphs_to_reserve (w, dim.width, w->left_margin_width);
right = margin_glyphs_to_reserve (w, dim.width, w->right_margin_width);
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_x == XFASTINT (w->left)
&& matrix->window_top_y == XFASTINT (w->top)
&& 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_width);
right = margin_glyphs_to_reserve (w, dim.width,
w->right_margin_width);
}
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_x == XFASTINT (w->left)
&& matrix->window_top_y == XFASTINT (w->top)
&& 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_x = XFASTINT (w->left);
matrix->window_top_y = XFASTINT (w->top);
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_DISPLAY_HEADER_LINE_HEIGHT (w);
max_y = WINDOW_DISPLAY_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_DISPLAY_HEADER_LINE_HEIGHT (w);
max_y = WINDOW_DISPLAY_HEIGHT_NO_MODE_LINE (w);
clear_glyph_row (row);
row->y = y;
row->ascent = row->phys_ascent = 0;
row->height = row->phys_height = CANON_Y_UNIT (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;
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)
{
if (row->inverse_p)
{
hash = -1;
}
else
{
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->truncated_on_left_p != b->truncated_on_left_p
|| a->inverse_p != b->inverse_p
|| a->fill_line_p != b->fill_line_p
|| a->truncated_on_right_p != b->truncated_on_right_p
|| a->overlay_arrow_p != b->overlay_arrow_p
|| a->continued_p != b->continued_p
|| a->indicate_empty_line_p != b->indicate_empty_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->right_margin_width)
!= w->desired_matrix->left_margin_glyphs)
|| (margin_glyphs_to_reserve (w, dim.width,
w->left_margin_width)
!= 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)
+ 2
+ 2);
}
#endif
return XINT (w->height);
}
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 = XFLOATINT (w->width) * CANON_X_UNIT (f);
return (((window_pixel_width + ch_width - 1)
/ ch_width)
+ 2
+ 1 + 1);
}
#endif
return XINT (w->width);
}
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_height = FRAME_HEIGHT (sf);
int frame_width = FRAME_WIDTH (sf);
int top_margin = FRAME_TOP_MARGIN (sf);
XSETFASTINT (root->top, top_margin);
XSETFASTINT (root->width, frame_width);
set_window_height (sf->root_window, frame_height - 1 - top_margin, 0);
XSETFASTINT (mini->top, frame_height - 1);
XSETFASTINT (mini->width, frame_width);
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 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 == XFASTINT (w->height));
xassert (m->matrix_w == XFASTINT (w->width));
for (i = 0; i < m->matrix_h; ++i)
{
struct glyph_row *r = m->rows + i;
struct glyph_row *fr = fm->rows + i + XFASTINT (w->top);
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;
r->inverse_p = fr->inverse_p;
}
}
}
}
}
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 ch_dim;
struct dim matrix_dim;
int pool_changed_p;
int window_change_flags;
int top_window_y;
if (!FRAME_LIVE_P (f))
return;
ch_dim.width = ch_dim.height = 1;
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_WIDTH (f)
&& matrix_dim.height == FRAME_HEIGHT (f));
if (display_completed
&& !FRAME_GARBAGED_P (f)
&& matrix_dim.width == f->current_matrix->matrix_w
&& matrix_dim.height == f->current_matrix->matrix_h)
{
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 dim ch_dim;
struct window *w;
xassert (FRAME_WINDOW_P (f) && FRAME_LIVE_P (f));
#ifdef HAVE_WINDOW_SYSTEM
ch_dim.width = FRAME_SMALLEST_CHAR_WIDTH (f);
ch_dim.height = FRAME_SMALLEST_FONT_HEIGHT (f);
#else
ch_dim.width = ch_dim.height = 1;
#endif
allocate_matrices_for_window_redisplay (XWINDOW (FRAME_ROOT_WINDOW (f)));
#ifndef USE_X_TOOLKIT
{
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, 0);
XSETFASTINT (w->left, 0);
XSETFASTINT (w->height, FRAME_MENU_BAR_LINES (f));
XSETFASTINT (w->width, FRAME_WINDOW_WIDTH (f));
allocate_matrices_for_window_redisplay (w);
}
#endif
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, FRAME_MENU_BAR_LINES (f));
XSETFASTINT (w->left, 0);
XSETFASTINT (w->height, FRAME_TOOL_BAR_LINES (f));
XSETFASTINT (w->width, FRAME_WINDOW_WIDTH (f));
allocate_matrices_for_window_redisplay (w);
}
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))
? XINT (DISP_BORDER_GLYPH (dp))
: '|');
}
}
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);
}
xassert (glyph_row_slice_p (window_row, frame_row));
#if GLYPH_DEBUG
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;
frame_row->inverse_p |= window_row->inverse_p;
++window_y;
++frame_y;
}
}
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;
xassert (NILP (w->hchild) && NILP (w->vchild));
xassert (WINDOW_FULL_WIDTH_P (w));
xassert (!FRAME_WINDOW_P (f));
window_row = w->current_matrix->rows;
window_row_end = window_row + w->current_matrix->nrows;
frame_row = f->current_matrix->rows + XFASTINT (w->top);
while (window_row < window_row_end)
{
int area;
for (area = LEFT_MARGIN_AREA; area <= LAST_AREA; ++area)
window_row->glyphs[area] = frame_row->glyphs[area];
++window_row, ++frame_row;
}
}
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 >= XFASTINT (w->top)
&& row < XFASTINT (w->top) + XFASTINT (w->height))
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_to);
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 += XFASTINT (w->top);
xassert (vpos >= 0 && vpos <= FRAME_HEIGHT (f));
return vpos;
}
static int
window_to_frame_hpos (w, hpos)
struct window *w;
int hpos;
{
struct frame *f = XFRAME (w->frame);
xassert (!FRAME_WINDOW_P (f));
hpos += XFASTINT (w->left);
return hpos;
}
#endif
DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0,
"Clear frame FRAME and output again what is supposed to appear on it.")
(frame)
Lisp_Object frame;
{
struct frame *f;
CHECK_LIVE_FRAME (frame, 0);
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, "",
"Clear and redisplay all visible frames.")
()
{
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->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_width)
? XFASTINT (w->left_margin_width)
: 0));
y = WINDOW_TO_FRAME_VPOS (w, w->cursor.vpos);
cursor_to (y, x);
}
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"));
UNCHANGED_MODIFIED = MODIFF;
BEG_UNCHANGED = GPT - BEG;
XSETFASTINT (w->last_point, PT);
w->last_cursor = w->cursor;
XSETFASTINT (w->last_modified, MODIFF);
XSETFASTINT (w->last_overlay_modified, OVERLAY_MODIFF);
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_BYTEPOS (row)
|| PT >= MATRIX_ROW_END_BYTEPOS (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_width)
? XFASTINT (w->left_margin_width)
: 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 (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))
{
Lisp_Object tem;
struct window *w = XWINDOW (f->tool_bar_window);
if (w->must_be_updated_p)
{
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 0
rif->flush_display (f);
#endif
}
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
}
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);
update_begin (f);
update_window (w, force_p);
update_end (f);
w->must_be_updated_p = 0;
}
}
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)
{
if (row->used[LEFT_MARGIN_AREA])
rif->fix_overlapping_area (w, row, LEFT_MARGIN_AREA);
if (row->used[TEXT_AREA])
rif->fix_overlapping_area (w, row, TEXT_AREA);
if (row->used[RIGHT_MARGIN_AREA])
rif->fix_overlapping_area (w, row, RIGHT_MARGIN_AREA);
if (row->phys_ascent > row->ascent && i > 0)
MATRIX_ROW (w->current_matrix, i - 1)->overlapped_p = 1;
if ((row->phys_height - row->phys_ascent
> row->height - row->ascent)
&& bottom_y < yb)
MATRIX_ROW (w->current_matrix, i + 1)->overlapped_p = 1;
}
if (bottom_y >= yb)
break;
}
}
#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;
int preempt_count = baud_rate / 2400 + 1;
extern int input_pending;
extern Lisp_Object do_mouse_tracking;
#if GLYPH_DEBUG
struct frame *f = XFRAME (WINDOW_FRAME (w));
extern struct frame *updating_frame;
#endif
xassert (FRAME_WINDOW_P (f));
xassert (updating_frame != NULL);
if (redisplay_dont_pause)
force_p = 1;
else
detect_input_pending ();
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);
changed_p = 1;
}
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;
}
if (header_line_row && header_line_row->enabled_p)
{
header_line_row->y = 0;
update_window_line (w, 0, &mouse_face_overwritten_p);
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 (!force_p && ++n_updated % preempt_count == 0)
detect_input_pending ();
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 (!paused_p && !w->pseudo_window_p)
{
if (changed_p && rif->fix_overlapping_area)
{
redraw_overlapped_rows (w, yb);
redraw_overlapping_rows (w, yb);
}
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
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->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;
}
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;
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]);
}
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->x + 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->x + 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->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_width))
{
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_width))
{
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->overlay_arrow_p != current_row->overlay_arrow_p
|| desired_row->truncated_on_left_p != current_row->truncated_on_left_p
|| desired_row->truncated_on_right_p != current_row->truncated_on_right_p
|| desired_row->continued_p != current_row->continued_p
|| desired_row->mode_line_p != current_row->mode_line_p
|| (desired_row->indicate_empty_line_p
!= current_row->indicate_empty_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 struct row_entry *add_row_entry P_ ((struct window *,
struct glyph_row *));
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
&& 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)
&& 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;
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 1;
}
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 (redisplay_dont_pause)
force_p = 1;
else if (!force_p && detect_input_pending ())
{
pause = 1;
goto do_pause;
}
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 ((i - 1) % preempt_count == 0)
detect_input_pending ();
update_frame_line (f, i);
}
}
pause = (i < FRAME_HEIGHT (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 = XINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top);
int row, col;
if (cursor_in_echo_area < 0)
{
row = top;
col = 0;
}
else
{
row = FRAME_HEIGHT (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_HEIGHT (f) - 1)
{
col = FRAME_LEFT_SCROLL_BAR_WIDTH (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 < XFASTINT (w->height))
{
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_width))
x += XFASTINT (w->left_margin_width);
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_HEIGHT (frame) * sizeof (int));
int *new_hash = (int *) alloca (FRAME_HEIGHT (frame) * sizeof (int));
int *draw_cost = (int *) alloca (FRAME_HEIGHT (frame) * sizeof (int));
int *old_draw_cost = (int *) alloca (FRAME_HEIGHT (frame) * sizeof (int));
register int i;
int free_at_end_vpos = FRAME_HEIGHT (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_HEIGHT (frame);
for (i = 0; i < FRAME_HEIGHT (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_HEIGHT (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_HEIGHT (frame))
return 1;
window_size = (FRAME_HEIGHT (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_HEIGHT (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_WINDOW_WIDTH((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;
if (desired_row->inverse_p
!= (current_row->enabled_p && current_row->inverse_p))
{
int n = current_row->enabled_p ? current_row->used[TEXT_AREA] : 0;
change_line_highlight (desired_row->inverse_p, vpos, vpos, n);
current_row->enabled_p = 0;
}
else
reassert_line_highlight (desired_row->inverse_p, vpos);
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 (!current_row->inverse_p)
{
if (!write_spaces_p)
while (olen > 0 && CHAR_GLYPH_SPACE_P (obody[olen-1]))
olen--;
}
else
{
while (olen < FRAME_WIDTH (f) - 1)
obody[olen++] = space_glyph;
}
}
current_row->enabled_p = 1;
current_row->used[TEXT_AREA] = desired_row->used[TEXT_AREA];
current_row->inverse_p = desired_row->inverse_p;
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_WINDOW_WIDTH (f))
{
cursor_to (vpos, nlen);
clear_end_of_line (FRAME_WINDOW_WIDTH (f));
}
else
cursor_to (vpos, 0);
make_current (desired_matrix, current_matrix, vpos);
return;
}
if (!desired_row->inverse_p)
{
if (!write_spaces_p)
while (nlen > 0 && CHAR_GLYPH_SPACE_P (nbody[nlen - 1]))
nlen--;
}
else
{
while (nlen < FRAME_WIDTH (f) - 1)
nbody[nlen++] = space_glyph;
}
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 || desired_row->inverse_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 = (desired_row->inverse_p || 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_WINDOW_WIDTH (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);
}
void
buffer_posn_from_coords (w, x, y, object, pos)
struct window *w;
int *x, *y;
Lisp_Object *object;
struct display_pos *pos;
{
struct it it;
struct buffer *old_current_buffer = current_buffer;
struct text_pos startp;
int left_area_width;
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);
left_area_width = WINDOW_DISPLAY_LEFT_AREA_PIXEL_WIDTH (w);
move_it_to (&it, -1, *x + it.first_visible_x - left_area_width, *y, -1,
MOVE_TO_X | MOVE_TO_Y);
*x = it.current_x - it.first_visible_x + left_area_width;
*y = it.current_y;
current_buffer = old_current_buffer;
*object = STRINGP (it.string) ? it.string : w->buffer;
*pos = it.current;
}
Lisp_Object
mode_line_string (w, x, y, mode_line_p, charpos)
struct window *w;
int x, y, mode_line_p;
int *charpos;
{
struct glyph_row *row;
struct glyph *glyph, *end;
struct frame *f = XFRAME (w->frame);
int x0;
Lisp_Object string = Qnil;
if (mode_line_p)
row = MATRIX_MODE_LINE_ROW (w->current_matrix);
else
row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
if (row->mode_line_p && row->enabled_p)
{
if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
x += FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
x += FRAME_LEFT_FLAGS_AREA_WIDTH (f);
glyph = row->glyphs[TEXT_AREA];
end = glyph + row->used[TEXT_AREA];
for (x0 = 0; glyph < end; x0 += glyph->pixel_width, ++glyph)
if (x >= x0 && x < x0 + glyph->pixel_width)
{
string = glyph->object;
*charpos = glyph->charpos;
break;
}
}
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;
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;
}
}
}
signal (SIGWINCH, window_change_signal);
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);
int height = FRAME_NEW_HEIGHT (f);
int width = FRAME_NEW_WIDTH (f);
if (height != 0 || width != 0)
change_frame_size (f, height, width, 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_window_width;
int count = specpdl_ptr - specpdl;
if (delay || (redisplaying_p && !safe))
{
FRAME_NEW_HEIGHT (f) = newheight;
FRAME_NEW_WIDTH (f) = newwidth;
delayed_size_change = 1;
return;
}
FRAME_NEW_HEIGHT (f) = 0;
FRAME_NEW_WIDTH (f) = 0;
if (newheight == 0)
newheight = FRAME_HEIGHT (f);
if (newwidth == 0)
newwidth = FRAME_WIDTH (f);
new_frame_window_width = FRAME_WINDOW_WIDTH_ARG (f, newwidth);
check_frame_size (f, &newheight, &newwidth);
if (newheight == FRAME_HEIGHT (f)
&& new_frame_window_width == FRAME_WINDOW_WIDTH (f))
return;
BLOCK_INPUT;
#ifdef MSDOS
dos_set_window_size (&newheight, &newwidth);
#endif
if (newheight != FRAME_HEIGHT (f))
{
if (FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
{
XSETFASTINT (XWINDOW (FRAME_ROOT_WINDOW (f))->top,
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,
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_window_width != FRAME_WINDOW_WIDTH (f))
{
set_window_width (FRAME_ROOT_WINDOW (f), new_frame_window_width, 0);
if (FRAME_HAS_MINIBUF_P (f))
set_window_width (FRAME_MINIBUF_WINDOW (f), new_frame_window_width, 0);
if (FRAME_TERMCAP_P (f) && !pretend)
FrameCols = newwidth;
if (WINDOWP (f->tool_bar_window))
XSETFASTINT (XWINDOW (f->tool_bar_window)->width, newwidth);
}
FRAME_HEIGHT (f) = newheight;
SET_FRAME_WIDTH (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);
SET_FRAME_GARBAGED (f);
calculate_costs (f);
UNBLOCK_INPUT;
record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
Fset_window_buffer (FRAME_SELECTED_WINDOW (f),
XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer);
unbind_to (count, Qnil);
}
DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript,
1, 1, "FOpen termscript file: ",
"Start writing all terminal output to FILE as well as the terminal.\n\
FILE = nil means just close any termscript file currently open.")
(file)
Lisp_Object file;
{
if (termscript != 0) fclose (termscript);
termscript = 0;
if (! NILP (file))
{
file = Fexpand_file_name (file, Qnil);
termscript = fopen (XSTRING (file)->data, "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,
"Send STRING to the terminal without alteration.\n\
Control characters in STRING will have terminal-dependent effects.")
(string)
Lisp_Object string;
{
CHECK_STRING (string, 0);
fwrite (XSTRING (string)->data, 1, STRING_BYTES (XSTRING (string)), stdout);
fflush (stdout);
if (termscript)
{
fwrite (XSTRING (string)->data, 1, STRING_BYTES (XSTRING (string)),
termscript);
fflush (termscript);
}
return Qnil;
}
DEFUN ("ding", Fding, Sding, 0, 1, 0,
"Beep, or flash the screen.\n\
Also, unless an argument is given,\n\
terminate any keyboard macro currently executing.")
(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,
"Pause, without updating display, for SECONDS seconds.\n\
SECONDS may be a floating-point value, meaning that you can wait for a\n\
fraction of a second. Optional second arg MILLISECONDS specifies an\n\
additional wait period, in milliseconds; this may be useful if your\n\
Emacs was built without floating point support.\n\
\(Not all operating systems support waiting for a fraction of a second.)")
(seconds, milliseconds)
Lisp_Object seconds, milliseconds;
{
int sec, usec;
if (NILP (milliseconds))
XSETINT (milliseconds, 0);
else
CHECK_NUMBER (milliseconds, 1);
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;
{
Lisp_Object zero;
XSETFASTINT (zero, 0);
wait_reading_process_input (sec, usec, zero, 0);
}
#if 0
immediate_quit = 1;
QUIT;
#ifdef VMS
sys_sleep (sec);
#else
#ifdef HAVE_SELECT
EMACS_GET_TIME (end_time);
EMACS_SET_SECS_USECS (timeout, sec, usec);
EMACS_ADD_TIME (end_time, end_time, timeout);
while (1)
{
EMACS_GET_TIME (timeout);
EMACS_SUB_TIME (timeout, end_time, timeout);
if (EMACS_TIME_NEG_P (timeout)
|| !select (1, 0, 0, 0, &timeout))
break;
}
#else
sleep (sec);
#endif
#endif
immediate_quit = 0;
#endif
return Qnil;
}
Lisp_Object
sit_for (sec, usec, reading, display, initial_display)
int sec, usec, reading, display, initial_display;
{
Lisp_Object read_kbd;
swallow_events (display);
if (detect_input_pending_run_timers (display))
return Qnil;
if (initial_display)
redisplay_preserve_echo_area (2);
if (sec == 0 && usec == 0)
return Qt;
#ifdef SIGIO
gobble_input (0);
#endif
XSETINT (read_kbd, reading ? -1 : 1);
wait_reading_process_input (sec, usec, read_kbd, display);
return detect_input_pending () ? Qnil : Qt;
}
DEFUN ("sit-for", Fsit_for, Ssit_for, 1, 3, 0,
"Perform redisplay, then wait for SECONDS seconds or until input is available.\n\
SECONDS may be a floating-point value, meaning that you can wait for a\n\
fraction of a second. Optional second arg MILLISECONDS specifies an\n\
additional wait period, in milliseconds; this may be useful if your\n\
Emacs was built without floating point support.\n\
\(Not all operating systems support waiting for a fraction of a second.)\n\
Optional third arg NODISP non-nil means don't redisplay, just wait for input.\n\
Redisplay is preempted as always if input arrives, and does not happen\n\
if input is available before it starts.\n\
Value is t if waited the full time with no input arriving.")
(seconds, milliseconds, nodisp)
Lisp_Object seconds, milliseconds, nodisp;
{
int sec, usec;
if (NILP (milliseconds))
XSETINT (milliseconds, 0);
else
CHECK_NUMBER (milliseconds, 1);
usec = XINT (milliseconds) * 1000;
{
double duration = extract_float (seconds);
sec = (int) duration;
usec += (duration - sec) * 1000000;
}
#ifndef EMACS_HAS_USECS
if (usec != 0 && sec == 0)
error ("millisecond `sit-for' not supported on %s", SYSTEM_TYPE);
#endif
return sit_for (sec, usec, 0, NILP (nodisp), NILP (nodisp));
}
static Lisp_Object frame_and_buffer_state;
DEFUN ("frame-or-buffer-changed-p", Fframe_or_buffer_changed_p,
Sframe_or_buffer_changed_p, 0, 0, 0,
"Return non-nil if the frame and buffer state appears to have changed.\n\
The state variable is an internal vector containing all frames and buffers,\n\
aside from buffers whose names start with space,\n\
along with the buffers' read-only and modified flags, which allows a fast\n\
check to see whether the menu bars might need to be recomputed.\n\
If this function returns non-nil, it updates the internal vector to reflect\n\
the current state.\n")
()
{
Lisp_Object tail, frame, buf;
Lisp_Object *vecp;
int n;
vecp = XVECTOR (frame_and_buffer_state)->contents;
FOR_EACH_FRAME (tail, frame)
{
if (!EQ (*vecp++, frame))
goto changed;
if (!EQ (*vecp++, XFRAME (frame)->name))
goto changed;
}
for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail))
{
buf = XCDR (XCAR (tail));
if (XSTRING (XBUFFER (buf)->name)->data[0] == ' ')
continue;
if (!EQ (*vecp++, buf))
goto changed;
if (!EQ (*vecp++, XBUFFER (buf)->read_only))
goto changed;
if (!EQ (*vecp++, Fbuffer_modified_p (buf)))
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 (n > XVECTOR (frame_and_buffer_state)->size
|| n + 20 < XVECTOR (frame_and_buffer_state)->size / 2)
frame_and_buffer_state = Fmake_vector (make_number (n + 20), Qlambda);
vecp = XVECTOR (frame_and_buffer_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 (XSTRING (XBUFFER (buf)->name)->data[0] == ' ')
continue;
*vecp++ = buf;
*vecp++ = XBUFFER (buf)->read_only;
*vecp++ = Fbuffer_modified_p (buf);
}
*vecp++ = Qlambda;
while (vecp - XVECTOR (frame_and_buffer_state)->contents
< XVECTOR (frame_and_buffer_state)->size)
*vecp++ = Qlambda;
if (vecp - XVECTOR (frame_and_buffer_state)->contents
> XVECTOR (frame_and_buffer_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 (! display_arg)
{
char *display;
#ifdef VMS
display = getenv ("DECW$DISPLAY");
#else
display = getenv ("DISPLAY");
#endif
display_arg = (display != 0 && *display != 0);
}
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 (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 macintosh
if (!inhibit_window_system)
{
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
fprintf (stderr, "Please set the environment variable TERM; see tset(1).\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_WINDOW_WIDTH (sf);
int height = FRAME_HEIGHT (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,
"Set the cursor-visibility flag of WINDOW to SHOW.\n\
WINDOW nil means use the selected window. SHOW non-nil means\n\
show a cursor in WINDOW in the next redisplay. SHOW nil means\n\
don't show a cursor.")
(window, show)
Lisp_Object window, show;
{
if (!redisplaying_p)
{
if (NILP (window))
window = selected_window;
else
CHECK_WINDOW (window, 2);
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,
"Value is non-nil if next redisplay will display a cursor in WINDOW.\n\
WINDOW nil or omitted means report on the selected window.")
(window)
Lisp_Object window;
{
struct window *w;
if (NILP (window))
window = selected_window;
else
CHECK_WINDOW (window, 2);
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 (&Ssit_for);
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,
"*The output baud rate of the terminal.\n\
On most systems, changing this value will affect the amount of padding\n\
and the other strategic decisions made during redisplay.");
DEFVAR_BOOL ("inverse-video", &inverse_video,
"*Non-nil means invert the entire frame display.\n\
This means everything is in inverse video which otherwise would not be.");
DEFVAR_BOOL ("visible-bell", &visible_bell,
"*Non-nil means try to flash the frame to represent a bell.");
DEFVAR_BOOL ("no-redraw-on-reenter", &no_redraw_on_reenter,
"*Non-nil means no need to redraw entire frame after suspending.\n\
A non-nil value is useful if the terminal can automatically preserve\n\
Emacs's frame display when you reenter Emacs.\n\
It is up to you to set this variable if your terminal can do that.");
DEFVAR_LISP ("window-system", &Vwindow_system,
"A symbol naming the window-system under which Emacs is running\n\
\(such as `x'), or nil if emacs is running on an ordinary terminal.");
DEFVAR_LISP ("window-system-version", &Vwindow_system_version,
"The version number of the window system in use.\n\
For X windows, this is 10 or 11.");
DEFVAR_BOOL ("cursor-in-echo-area", &cursor_in_echo_area,
"Non-nil means put cursor in minibuffer, at end of any message there.");
DEFVAR_LISP ("glyph-table", &Vglyph_table,
"Table defining how to output a glyph code to the frame.\n\
If not nil, this is a vector indexed by glyph code to define the glyph.\n\
Each element can be:\n\
integer: a glyph code which this glyph is an alias for.\n\
string: output this glyph using that string (not impl. in X windows).\n\
nil: this glyph mod 524288 is the code of a character to output,\n\
and this glyph / 524288 is the face number (see `face-id') to use\n\
while outputting it.");
Vglyph_table = Qnil;
DEFVAR_LISP ("standard-display-table", &Vstandard_display_table,
"Display table to use for buffers that specify none.\n\
See `buffer-display-table' for more information.");
Vstandard_display_table = Qnil;
DEFVAR_BOOL ("redisplay-dont-pause", &redisplay_dont_pause,
"*Non-nil means update isn't paused when input is detected.");
redisplay_dont_pause = 0;
#ifdef CANNOT_DUMP
if (noninteractive)
#endif
{
Vwindow_system = Qnil;
Vwindow_system_version = Qnil;
}
}