[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] Changes to emacs/src/dispnew.c [emacs-unicode-2]
From: |
Kenichi Handa |
Subject: |
[Emacs-diffs] Changes to emacs/src/dispnew.c [emacs-unicode-2] |
Date: |
Mon, 08 Sep 2003 08:48:47 -0400 |
Index: emacs/src/dispnew.c
diff -c /dev/null emacs/src/dispnew.c:1.318.2.1
*** /dev/null Mon Sep 8 08:48:47 2003
--- emacs/src/dispnew.c Mon Sep 8 08:48:10 2003
***************
*** 0 ****
--- 1,6723 ----
+ /* Updating of data structures for redisplay.
+ Copyright (C) 1985,86,87,88,93,94,95,97,98,1999,2000,01,02,2003
+ Free Software Foundation, Inc.
+
+ This file is part of GNU Emacs.
+
+ GNU Emacs is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Emacs is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Emacs; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+ #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"
+ /* cm.h must come after dispextern.h on Windows. */
+ #include "dispextern.h"
+ #include "cm.h"
+ #include "buffer.h"
+ #include "character.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"
+
+ /* I don't know why DEC Alpha OSF1 fail to compile this file if we
+ include the following file. */
+ /* #include "systty.h" */
+ #include "syssignal.h"
+
+ #ifdef HAVE_X_WINDOWS
+ #include "xterm.h"
+ #endif /* HAVE_X_WINDOWS */
+
+ #ifdef HAVE_NTGUI
+ #include "w32term.h"
+ #endif /* HAVE_NTGUI */
+
+ #ifdef MAC_OS
+ #include "macterm.h"
+ #endif /* MAC_OS */
+
+ /* Include systime.h after xterm.h to avoid double inclusion of time.h. */
+
+ #include "systime.h"
+ #include <errno.h>
+
+ /* To get the prototype for `sleep'. */
+
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+ #endif
+
+ /* Get number of chars of output now in the buffer of a stdio stream.
+ This ought to be built in in stdio, but it isn't. Some s- files
+ override this because their stdio internals differ. */
+
+ #ifdef __GNU_LIBRARY__
+
+ /* The s- file might have overridden the definition with one that
+ works for the system's C library. But we are using the GNU C
+ library, so this is the right definition for every system. */
+
+ #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 /* not __GNU_LIBRARY__ */
+ #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 /* not __GNU_LIBRARY__ */
+
+ #if defined(HAVE_TERM_H) && defined (GNU_LINUX) && defined (HAVE_LIBNCURSES)
+ #include <term.h> /* for tgetent */
+ #endif
+
+ /* Structure to pass dimensions around. Used for character bounding
+ boxes, glyph matrix dimensions and alike. */
+
+ struct dim
+ {
+ int width;
+ int height;
+ };
+
+
+ /* Function prototypes. */
+
+ 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));
+
+
+ /* Non-zero means don't pause redisplay for pending input. (This is
+ for debugging and for a future implementation of EDT-like
+ scrolling. */
+
+ int redisplay_dont_pause;
+
+ /* Nonzero upon entry to redisplay means do not assume anything about
+ current contents of actual terminal frame; clear and redraw it. */
+
+ int frame_garbaged;
+
+ /* Nonzero means last display completed. Zero means it was preempted. */
+
+ int display_completed;
+
+ /* Lisp variable visible-bell; enables use of screen-flash instead of
+ audible bell. */
+
+ int visible_bell;
+
+ /* Invert the color of the whole frame, at a low level. */
+
+ int inverse_video;
+
+ /* Line speed of the terminal. */
+
+ EMACS_INT baud_rate;
+
+ /* Either nil or a symbol naming the window system under which Emacs
+ is running. */
+
+ Lisp_Object Vwindow_system;
+
+ /* Version number of X windows: 10, 11 or nil. */
+
+ Lisp_Object Vwindow_system_version;
+
+ /* Vector of glyph definitions. Indexed by glyph number, the contents
+ are a string which is how to output the glyph.
+
+ If Vglyph_table is nil, a glyph is output by using its low 8 bits
+ as a character code.
+
+ This is an obsolete feature that is no longer used. The variable
+ is retained for compatibility. */
+
+ Lisp_Object Vglyph_table;
+
+ /* Display table to use for vectors that don't specify their own. */
+
+ Lisp_Object Vstandard_display_table;
+
+ /* Nonzero means reading single-character input with prompt so put
+ cursor on mini-buffer after the prompt. Positive means at end of
+ text in echo area; negative means at beginning of line. */
+
+ int cursor_in_echo_area;
+
+ Lisp_Object Qdisplay_table, Qredisplay_dont_pause;
+
+
+ /* The currently selected frame. In a single-frame version, this
+ variable always equals the_only_frame. */
+
+ Lisp_Object selected_frame;
+
+ /* A frame which is not just a mini-buffer, or 0 if there are no such
+ frames. This is usually the most recent such frame that was
+ selected. In a single-frame version, this variable always holds
+ the address of the_only_frame. */
+
+ struct frame *last_nonminibuf_frame;
+
+ /* Stdio stream being used for copy of all output. */
+
+ FILE *termscript;
+
+ /* Structure for info on cursor positioning. */
+
+ struct cm Wcm;
+
+ /* 1 means SIGWINCH happened when not safe. */
+
+ int delayed_size_change;
+
+ /* 1 means glyph initialization has been completed at startup. */
+
+ static int glyphs_initialized_initially_p;
+
+ /* Updated window if != 0. Set by update_window. */
+
+ struct window *updated_window;
+
+ /* Glyph row updated in update_window_line, and area that is updated. */
+
+ struct glyph_row *updated_row;
+ int updated_area;
+
+ /* A glyph for a space. */
+
+ struct glyph space_glyph;
+
+ /* Non-zero means update has been performed directly, so that there's
+ no need for redisplay_internal to do much work. Set by
+ direct_output_for_insert. */
+
+ int redisplay_performed_directly_p;
+
+ /* Counts of allocated structures. These counts serve to diagnose
+ memory leaks and double frees. */
+
+ int glyph_matrix_count;
+ int glyph_pool_count;
+
+ /* If non-null, the frame whose frame matrices are manipulated. If
+ null, window matrices are worked on. */
+
+ static struct frame *frame_matrix_frame;
+
+ /* Current interface for window-based redisplay. Set from init_xterm.
+ A null value means we are not using window-based redisplay. */
+
+ struct redisplay_interface *rif;
+
+ /* Non-zero means that fonts have been loaded since the last glyph
+ matrix adjustments. Redisplay must stop, and glyph matrices must
+ be adjusted when this flag becomes non-zero during display. The
+ reason fonts can be loaded so late is that fonts of fontsets are
+ loaded on demand. */
+
+ int fonts_changed_p;
+
+ /* Convert vpos and hpos from frame to window and vice versa.
+ This may only be used for terminal frames. */
+
+ #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))
+
+ /* One element of the ring buffer containing redisplay history
+ information. */
+
+ struct redisplay_history
+ {
+ char trace[512 + 100];
+ };
+
+ /* The size of the history buffer. */
+
+ #define REDISPLAY_HISTORY_SIZE 30
+
+ /* The redisplay history buffer. */
+
+ static struct redisplay_history redisplay_history[REDISPLAY_HISTORY_SIZE];
+
+ /* Next free entry in redisplay_history. */
+
+ static int history_idx;
+
+ /* A tick that's incremented each time something is added to the
+ history. */
+
+ 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));
+
+
+ /* Add to the redisplay history how window W has been displayed.
+ MSG is a trace containing the information how W's glyph matrix
+ has been constructed. PAUSED_P non-zero means that the update
+ has been interrupted for pending input. */
+
+ static void
+ add_window_display_history (w, msg, paused_p)
+ struct window *w;
+ char *msg;
+ int paused_p;
+ {
+ char *buf;
+
+ if (history_idx >= REDISPLAY_HISTORY_SIZE)
+ history_idx = 0;
+ buf = redisplay_history[history_idx].trace;
+ ++history_idx;
+
+ sprintf (buf, "%d: window %p (`%s')%s\n",
+ history_tick++,
+ w,
+ ((BUFFERP (w->buffer)
+ && STRINGP (XBUFFER (w->buffer)->name))
+ ? (char *) SDATA (XBUFFER (w->buffer)->name)
+ : "???"),
+ paused_p ? " ***paused***" : "");
+ strcat (buf, msg);
+ }
+
+
+ /* Add to the redisplay history that frame F has been displayed.
+ PAUSED_P non-zero means that the update has been interrupted for
+ pending input. */
+
+ static void
+ add_frame_display_history (f, paused_p)
+ struct frame *f;
+ int paused_p;
+ {
+ char *buf;
+
+ if (history_idx >= REDISPLAY_HISTORY_SIZE)
+ history_idx = 0;
+ buf = redisplay_history[history_idx].trace;
+ ++history_idx;
+
+ sprintf (buf, "%d: update frame %p%s",
+ history_tick++,
+ f, paused_p ? " ***paused***" : "");
+ }
+
+
+ DEFUN ("dump-redisplay-history", Fdump_redisplay_history,
+ Sdump_redisplay_history, 0, 0, "",
+ doc: /* 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 /* GLYPH_DEBUG == 0 */
+
+ #define WINDOW_TO_FRAME_VPOS(W, VPOS) ((VPOS) + WINDOW_TOP_EDGE_LINE (W))
+ #define WINDOW_TO_FRAME_HPOS(W, HPOS) ((HPOS) + WINDOW_LEFT_EDGE_COL (W))
+
+ #endif /* GLYPH_DEBUG == 0 */
+
+
+ /* Like bcopy except never gets confused by overlap. Let this be the
+ first function defined in this file, or change emacs.c where the
+ address of this function is used. */
+
+ void
+ safe_bcopy (from, to, size)
+ const char *from;
+ char *to;
+ int size;
+ {
+ if (size <= 0 || from == to)
+ return;
+
+ /* If the source and destination don't overlap, then bcopy can
+ handle it. If they do overlap, but the destination is lower in
+ memory than the source, we'll assume bcopy can handle that. */
+ if (to < from || from + size <= to)
+ bcopy (from, to, size);
+
+ /* Otherwise, we'll copy from the end. */
+ else
+ {
+ register const char *endf = from + size;
+ register char *endt = to + size;
+
+ /* If TO - FROM is large, then we should break the copy into
+ nonoverlapping chunks of TO - FROM bytes each. However, if
+ TO - FROM is small, then the bcopy function call overhead
+ makes this not worth it. The crossover point could be about
+ anywhere. Since I don't think the obvious copy loop is too
+ bad, I'm trying to err in its favor. */
+ 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);
+ }
+
+ /* If SIZE wasn't a multiple of TO - FROM, there will be a
+ little left over. The amount left over is (endt + (to -
+ from)) - to, which is endt - from. */
+ bcopy (from, to, endt - from);
+ }
+ }
+ }
+
+
+
+ /***********************************************************************
+ Glyph Matrices
+ ***********************************************************************/
+
+ /* Allocate and return a glyph_matrix structure. POOL is the glyph
+ pool from which memory for the matrix should be allocated, or null
+ for window-based redisplay where no glyph pools are used. The
+ member `pool' of the glyph matrix structure returned is set to
+ POOL, the structure is otherwise zeroed. */
+
+ struct glyph_matrix *
+ new_glyph_matrix (pool)
+ struct glyph_pool *pool;
+ {
+ struct glyph_matrix *result;
+
+ /* Allocate and clear. */
+ result = (struct glyph_matrix *) xmalloc (sizeof *result);
+ bzero (result, sizeof *result);
+
+ /* Increment number of allocated matrices. This count is used
+ to detect memory leaks. */
+ ++glyph_matrix_count;
+
+ /* Set pool and return. */
+ result->pool = pool;
+ return result;
+ }
+
+
+ /* Free glyph matrix MATRIX. Passing in a null MATRIX is allowed.
+
+ The global counter glyph_matrix_count is decremented when a matrix
+ is freed. If the count gets negative, more structures were freed
+ than allocated, i.e. one matrix was freed more than once or a bogus
+ pointer was passed to this function.
+
+ If MATRIX->pool is null, this means that the matrix manages its own
+ glyph memory---this is done for matrices on X frames. Freeing the
+ matrix also frees the glyph memory in this case. */
+
+ static void
+ free_glyph_matrix (matrix)
+ struct glyph_matrix *matrix;
+ {
+ if (matrix)
+ {
+ int i;
+
+ /* Detect the case that more matrices are freed than were
+ allocated. */
+ if (--glyph_matrix_count < 0)
+ abort ();
+
+ /* Free glyph memory if MATRIX owns it. */
+ if (matrix->pool == NULL)
+ for (i = 0; i < matrix->rows_allocated; ++i)
+ xfree (matrix->rows[i].glyphs[LEFT_MARGIN_AREA]);
+
+ /* Free row structures and the matrix itself. */
+ xfree (matrix->rows);
+ xfree (matrix);
+ }
+ }
+
+
+ /* Return the number of glyphs to reserve for a marginal area of
+ window W. TOTAL_GLYPHS is the number of glyphs in a complete
+ display line of window W. MARGIN gives the width of the marginal
+ area in canonical character units. MARGIN should be an integer
+ or a float. */
+
+ static int
+ margin_glyphs_to_reserve (w, total_glyphs, margin)
+ struct window *w;
+ int total_glyphs;
+ Lisp_Object margin;
+ {
+ int n;
+
+ if (NUMBERP (margin))
+ {
+ int width = XFASTINT (w->total_cols);
+ double d = max (0, XFLOATINT (margin));
+ d = min (width / 2 - 1, d);
+ n = (int) ((double) total_glyphs / width * d);
+ }
+ else
+ n = 0;
+
+ return n;
+ }
+
+
+ /* Adjust glyph matrix MATRIX on window W or on a frame to changed
+ window sizes.
+
+ W is null if the function is called for a frame glyph matrix.
+ Otherwise it is the window MATRIX is a member of. X and Y are the
+ indices of the first column and row of MATRIX within the frame
+ matrix, if such a matrix exists. They are zero for purely
+ window-based redisplay. DIM is the needed size of the matrix.
+
+ In window-based redisplay, where no frame matrices exist, glyph
+ matrices manage their own glyph storage. Otherwise, they allocate
+ storage from a common frame glyph pool which can be found in
+ MATRIX->pool.
+
+ The reason for this memory management strategy is to avoid complete
+ frame redraws if possible. When we allocate from a common pool, a
+ change of the location or size of a sub-matrix within the pool
+ requires a complete redisplay of the frame because we cannot easily
+ make sure that the current matrices of all windows still agree with
+ what is displayed on the screen. While this is usually fast, it
+ leads to screen flickering. */
+
+ static void
+ adjust_glyph_matrix (w, matrix, x, y, dim)
+ struct window *w;
+ struct glyph_matrix *matrix;
+ int x, y;
+ struct dim dim;
+ {
+ int i;
+ int new_rows;
+ int marginal_areas_changed_p = 0;
+ int header_line_changed_p = 0;
+ int header_line_p = 0;
+ int left = -1, right = -1;
+ int window_width = -1, window_height;
+
+ /* See if W had a header line that has disappeared now, or vice versa. */
+ 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;
+
+ /* Do nothing if MATRIX' size, position, vscroll, and marginal areas
+ haven't changed. This optimization is important because preserving
+ the matrix means preventing redisplay. */
+ if (matrix->pool == NULL)
+ {
+ window_box (w, -1, 0, 0, &window_width, &window_height);
+ left = margin_glyphs_to_reserve (w, dim.width, w->left_margin_cols);
+ right = margin_glyphs_to_reserve (w, dim.width, w->right_margin_cols);
+ xassert (left >= 0 && right >= 0);
+ marginal_areas_changed_p = (left != matrix->left_margin_glyphs
+ || right != matrix->right_margin_glyphs);
+
+ if (!marginal_areas_changed_p
+ && !fonts_changed_p
+ && !header_line_changed_p
+ && matrix->window_left_col == WINDOW_LEFT_EDGE_COL (w)
+ && matrix->window_top_line == WINDOW_TOP_EDGE_LINE (w)
+ && matrix->window_height == window_height
+ && matrix->window_vscroll == w->vscroll
+ && matrix->window_width == window_width)
+ return;
+ }
+
+ /* Enlarge MATRIX->rows if necessary. New rows are cleared. */
+ 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 POOL is not null, MATRIX is a frame matrix or a window matrix
+ on a frame not using window-based redisplay. Set up pointers for
+ each row into the glyph pool. */
+ if (matrix->pool)
+ {
+ xassert (matrix->pool->glyphs);
+
+ if (w)
+ {
+ left = margin_glyphs_to_reserve (w, dim.width,
+ w->left_margin_cols);
+ right = margin_glyphs_to_reserve (w, dim.width,
+ w->right_margin_cols);
+ }
+ else
+ left = right = 0;
+
+ for (i = 0; i < dim.height; ++i)
+ {
+ struct glyph_row *row = &matrix->rows[i];
+
+ row->glyphs[LEFT_MARGIN_AREA]
+ = (matrix->pool->glyphs
+ + (y + i) * matrix->pool->ncolumns
+ + x);
+
+ if (w == NULL
+ || row == matrix->rows + dim.height - 1
+ || (row == matrix->rows && matrix->header_line_p))
+ {
+ row->glyphs[TEXT_AREA]
+ = row->glyphs[LEFT_MARGIN_AREA];
+ row->glyphs[RIGHT_MARGIN_AREA]
+ = row->glyphs[TEXT_AREA] + dim.width;
+ row->glyphs[LAST_AREA]
+ = row->glyphs[RIGHT_MARGIN_AREA];
+ }
+ else
+ {
+ row->glyphs[TEXT_AREA]
+ = row->glyphs[LEFT_MARGIN_AREA] + left;
+ row->glyphs[RIGHT_MARGIN_AREA]
+ = row->glyphs[TEXT_AREA] + dim.width - left - right;
+ row->glyphs[LAST_AREA]
+ = row->glyphs[LEFT_MARGIN_AREA] + dim.width;
+ }
+ }
+
+ matrix->left_margin_glyphs = left;
+ matrix->right_margin_glyphs = right;
+ }
+ else
+ {
+ /* If MATRIX->pool is null, MATRIX is responsible for managing
+ its own memory. Allocate glyph memory from the heap. */
+ 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)));
+
+ /* The mode line never has marginal areas. */
+ 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;
+ }
+
+ /* Number of rows to be used by MATRIX. */
+ matrix->nrows = dim.height;
+ xassert (matrix->nrows >= 0);
+
+ if (w)
+ {
+ if (matrix == w->current_matrix)
+ {
+ /* Mark rows in a current matrix of a window as not having
+ valid contents. It's important to not do this for
+ desired matrices. When Emacs starts, it may already be
+ building desired matrices when this function runs. */
+ if (window_width < 0)
+ window_width = window_box_width (w, -1);
+
+ /* Optimize the case that only the height has changed (C-x 2,
+ upper window). Invalidate all rows that are no longer part
+ of the window. */
+ if (!marginal_areas_changed_p
+ && !header_line_changed_p
+ && new_rows == 0
+ && dim.width == matrix->matrix_w
+ && matrix->window_left_col == WINDOW_LEFT_EDGE_COL (w)
+ && matrix->window_top_line == WINDOW_TOP_EDGE_LINE (w)
+ && matrix->window_width == window_width)
+ {
+ /* Find the last row in the window. */
+ for (i = 0; i < matrix->nrows && matrix->rows[i].enabled_p; ++i)
+ if (MATRIX_ROW_BOTTOM_Y (matrix->rows + i) >= window_height)
+ {
+ ++i;
+ break;
+ }
+
+ /* Window end is invalid, if inside of the rows that
+ are invalidated below. */
+ 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)
+ {
+ /* Rows in desired matrices always have to be cleared;
+ redisplay expects this is the case when it runs, so it
+ had better be the case when we adjust matrices between
+ redisplays. */
+ for (i = 0; i < matrix->nrows; ++i)
+ matrix->rows[i].enabled_p = 0;
+ }
+ }
+
+
+ /* Remember last values to be able to optimize frame redraws. */
+ matrix->matrix_x = x;
+ matrix->matrix_y = y;
+ matrix->matrix_w = dim.width;
+ matrix->matrix_h = dim.height;
+
+ /* Record the top y location and height of W at the time the matrix
+ was last adjusted. This is used to optimize redisplay above. */
+ if (w)
+ {
+ matrix->window_left_col = WINDOW_LEFT_EDGE_COL (w);
+ matrix->window_top_line = WINDOW_TOP_EDGE_LINE (w);
+ matrix->window_height = window_height;
+ matrix->window_width = window_width;
+ matrix->window_vscroll = w->vscroll;
+ }
+ }
+
+
+ /* Reverse the contents of rows in MATRIX between START and END. The
+ contents of the row at END - 1 end up at START, END - 2 at START +
+ 1 etc. This is part of the implementation of rotate_matrix (see
+ below). */
+
+ 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)
+ {
+ /* Non-ISO HP/UX compiler doesn't like auto struct
+ initialization. */
+ struct glyph_row temp;
+ temp = matrix->rows[i];
+ matrix->rows[i] = matrix->rows[j];
+ matrix->rows[j] = temp;
+ }
+ }
+
+
+ /* Rotate the contents of rows in MATRIX in the range FIRST .. LAST -
+ 1 by BY positions. BY < 0 means rotate left, i.e. towards lower
+ indices. (Note: this does not copy glyphs, only glyph pointers in
+ row structures are moved around).
+
+ The algorithm used for rotating the vector was, I believe, first
+ described by Kernighan. See the vector R as consisting of two
+ sub-vectors AB, where A has length BY for BY >= 0. The result
+ after rotating is then BA. Reverse both sub-vectors to get ArBr
+ and reverse the result to get (ArBr)r which is BA. Similar for
+ rotating right. */
+
+ void
+ rotate_matrix (matrix, first, last, by)
+ struct glyph_matrix *matrix;
+ int first, last, by;
+ {
+ if (by < 0)
+ {
+ /* Up (rotate left, i.e. towards lower indices). */
+ by = -by;
+ reverse_rows (matrix, first, first + by);
+ reverse_rows (matrix, first + by, last);
+ reverse_rows (matrix, first, last);
+ }
+ else if (by > 0)
+ {
+ /* Down (rotate right, i.e. towards higher indices). */
+ reverse_rows (matrix, last - by, last);
+ reverse_rows (matrix, first, last - by);
+ reverse_rows (matrix, first, last);
+ }
+ }
+
+
+ /* Increment buffer positions in glyph rows of MATRIX. Do it for rows
+ with indices START <= index < END. Increment positions by DELTA/
+ DELTA_BYTES. */
+
+ void
+ increment_matrix_positions (matrix, start, end, delta, delta_bytes)
+ struct glyph_matrix *matrix;
+ int start, end, delta, delta_bytes;
+ {
+ /* Check that START and END are reasonable values. */
+ 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);
+ }
+
+
+ /* Enable a range of rows in glyph matrix MATRIX. START and END are
+ the row indices of the first and last + 1 row to enable. If
+ ENABLED_P is non-zero, enabled_p flags in rows will be set to 1. */
+
+ 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;
+ }
+
+
+ /* Clear MATRIX.
+
+ This empties all rows in MATRIX by setting the enabled_p flag for
+ all rows of the matrix to zero. The function prepare_desired_row
+ will eventually really clear a row when it sees one with a zero
+ enabled_p flag.
+
+ Resets update hints to defaults value. The only update hint
+ currently present is the flag MATRIX->no_scrolling_p. */
+
+ 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;
+ }
+ }
+
+
+ /* Shift part of the glyph matrix MATRIX of window W up or down.
+ Increment y-positions in glyph rows between START and END by DY,
+ and recompute their visible height. */
+
+ void
+ shift_glyph_matrix (w, matrix, start, end, dy)
+ struct window *w;
+ struct glyph_matrix *matrix;
+ int start, end, dy;
+ {
+ int min_y, max_y;
+
+ xassert (start <= end);
+ xassert (start >= 0 && start < matrix->nrows);
+ xassert (end >= 0 && end <= matrix->nrows);
+
+ min_y = WINDOW_HEADER_LINE_HEIGHT (w);
+ max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (w);
+
+ for (; start < end; ++start)
+ {
+ struct glyph_row *row = &matrix->rows[start];
+
+ row->y += dy;
+ row->visible_height = row->height;
+
+ if (row->y < min_y)
+ row->visible_height -= min_y - row->y;
+ if (row->y + row->height > max_y)
+ row->visible_height -= row->y + row->height - max_y;
+ }
+ }
+
+
+ /* Mark all rows in current matrices of frame F as invalid. Marking
+ invalid is done by setting enabled_p to zero for all rows in a
+ current matrix. */
+
+ void
+ clear_current_matrices (f)
+ register struct frame *f;
+ {
+ /* Clear frame current matrix, if we have one. */
+ if (f->current_matrix)
+ clear_glyph_matrix (f->current_matrix);
+
+ /* Clear the matrix of the menu bar window, if such a window exists.
+ The menu bar window is currently used to display menus on X when
+ no toolkit support is compiled in. */
+ if (WINDOWP (f->menu_bar_window))
+ clear_glyph_matrix (XWINDOW (f->menu_bar_window)->current_matrix);
+
+ /* Clear the matrix of the tool-bar window, if any. */
+ if (WINDOWP (f->tool_bar_window))
+ clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
+
+ /* Clear current window matrices. */
+ xassert (WINDOWP (FRAME_ROOT_WINDOW (f)));
+ clear_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)), 0);
+ }
+
+
+ /* Clear out all display lines of F for a coming redisplay. */
+
+ 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);
+
+ /* Do it for window matrices. */
+ xassert (WINDOWP (FRAME_ROOT_WINDOW (f)));
+ clear_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)), 1);
+ }
+
+
+ /* Clear matrices in window tree rooted in W. If DESIRED_P is
+ non-zero clear desired matrices, otherwise clear current matrices. */
+
+ 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);
+ }
+ }
+
+
+
+ /***********************************************************************
+ Glyph Rows
+
+ See dispextern.h for an overall explanation of glyph rows.
+ ***********************************************************************/
+
+ /* Clear glyph row ROW. Do it in a way that makes it robust against
+ changes in the glyph_row structure, i.e. addition or removal of
+ structure members. */
+
+ static struct glyph_row null_row;
+
+ void
+ clear_glyph_row (row)
+ struct glyph_row *row;
+ {
+ struct glyph *p[1 + LAST_AREA];
+
+ /* Save pointers. */
+ 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];
+
+ /* Clear. */
+ *row = null_row;
+
+ /* Restore pointers. */
+ 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 /* At some point, some bit-fields of struct glyph were not set,
+ which made glyphs unequal when compared with GLYPH_EQUAL_P.
+ Redisplay outputs such glyphs, and flickering effects were
+ the result. This also depended on the contents of memory
+ returned by xmalloc. If flickering happens again, activate
+ the code below. If the flickering is gone with that, chances
+ are that the flickering has the same reason as here. */
+ bzero (p[0], (char *) p[LAST_AREA] - (char *) p[0]);
+ #endif
+ }
+
+
+ /* Make ROW an empty, enabled row of canonical character height,
+ in window W starting at y-position Y. */
+
+ void
+ blank_row (w, row, y)
+ struct window *w;
+ struct glyph_row *row;
+ int y;
+ {
+ int min_y, max_y;
+
+ min_y = WINDOW_HEADER_LINE_HEIGHT (w);
+ max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (w);
+
+ clear_glyph_row (row);
+ row->y = y;
+ row->ascent = row->phys_ascent = 0;
+ row->height = row->phys_height = FRAME_LINE_HEIGHT (XFRAME (w->frame));
+ row->visible_height = row->height;
+
+ if (row->y < min_y)
+ row->visible_height -= min_y - row->y;
+ if (row->y + row->height > max_y)
+ row->visible_height -= row->y + row->height - max_y;
+
+ row->enabled_p = 1;
+ }
+
+
+ /* Increment buffer positions in glyph row ROW. DELTA and DELTA_BYTES
+ are the amounts by which to change positions. Note that the first
+ glyph of the text area of a row can have a buffer position even if
+ the used count of the text area is zero. Such rows display line
+ ends. */
+
+ void
+ increment_row_positions (row, delta, delta_bytes)
+ struct glyph_row *row;
+ int delta, delta_bytes;
+ {
+ int area, i;
+
+ /* Increment start and end positions. */
+ 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;
+
+ /* Increment positions in glyphs. */
+ 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;
+
+ /* Capture the case of rows displaying a line end. */
+ if (row->used[TEXT_AREA] == 0
+ && MATRIX_ROW_DISPLAYS_TEXT_P (row))
+ row->glyphs[TEXT_AREA]->charpos += delta;
+ }
+
+
+ #if 0
+ /* Swap glyphs between two glyph rows A and B. This exchanges glyph
+ contents, i.e. glyph structure contents are exchanged between A and
+ B without changing glyph pointers in A and B. */
+
+ static void
+ swap_glyphs_in_rows (a, b)
+ struct glyph_row *a, *b;
+ {
+ int area;
+
+ for (area = 0; area < LAST_AREA; ++area)
+ {
+ /* Number of glyphs to swap. */
+ int max_used = max (a->used[area], b->used[area]);
+
+ /* Start of glyphs in area of row A. */
+ struct glyph *glyph_a = a->glyphs[area];
+
+ /* End + 1 of glyphs in area of row A. */
+ struct glyph *glyph_a_end = a->glyphs[max_used];
+
+ /* Start of glyphs in area of row B. */
+ struct glyph *glyph_b = b->glyphs[area];
+
+ while (glyph_a < glyph_a_end)
+ {
+ /* Non-ISO HP/UX compiler doesn't like auto struct
+ initialization. */
+ struct glyph temp;
+ temp = *glyph_a;
+ *glyph_a = *glyph_b;
+ *glyph_b = temp;
+ ++glyph_a;
+ ++glyph_b;
+ }
+ }
+ }
+
+ #endif /* 0 */
+
+ /* Exchange pointers to glyph memory between glyph rows A and B. */
+
+ 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;
+ }
+ }
+
+
+ /* Copy glyph row structure FROM to glyph row structure TO, except
+ that glyph pointers in the structures are left unchanged. */
+
+ INLINE void
+ copy_row_except_pointers (to, from)
+ struct glyph_row *to, *from;
+ {
+ struct glyph *pointers[1 + LAST_AREA];
+
+ /* Save glyph pointers of TO. */
+ bcopy (to->glyphs, pointers, sizeof to->glyphs);
+
+ /* Do a structure assignment. */
+ *to = *from;
+
+ /* Restore original pointers of TO. */
+ bcopy (pointers, to->glyphs, sizeof to->glyphs);
+ }
+
+
+ /* Copy contents of glyph row FROM to glyph row TO. Glyph pointers in
+ TO and FROM are left unchanged. Glyph contents are copied from the
+ glyph memory of FROM to the glyph memory of TO. Increment buffer
+ positions in row TO by DELTA/ DELTA_BYTES. */
+
+ void
+ copy_glyph_row_contents (to, from, delta, delta_bytes)
+ struct glyph_row *to, *from;
+ int delta, delta_bytes;
+ {
+ int area;
+
+ /* This is like a structure assignment TO = FROM, except that
+ glyph pointers in the rows are left unchanged. */
+ copy_row_except_pointers (to, from);
+
+ /* Copy glyphs from FROM to TO. */
+ 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 buffer positions in TO by DELTA. */
+ increment_row_positions (to, delta, delta_bytes);
+ }
+
+
+ /* Assign glyph row FROM to glyph row TO. This works like a structure
+ assignment TO = FROM, except that glyph pointers are not copied but
+ exchanged between TO and FROM. Pointers must be exchanged to avoid
+ a memory leak. */
+
+ static INLINE void
+ assign_row (to, from)
+ struct glyph_row *to, *from;
+ {
+ swap_glyph_pointers (to, from);
+ copy_row_except_pointers (to, from);
+ }
+
+
+ /* Test whether the glyph memory of the glyph row WINDOW_ROW, which is
+ a row in a window matrix, is a slice of the glyph memory of the
+ glyph row FRAME_ROW which is a row in a frame glyph matrix. Value
+ is non-zero if the glyph memory of WINDOW_ROW is part of the glyph
+ memory of FRAME_ROW. */
+
+ #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 /* GLYPH_DEBUG */
+
+ #if 0
+
+ /* Find the row in the window glyph matrix WINDOW_MATRIX being a slice
+ of ROW in the frame matrix FRAME_MATRIX. Value is null if no row
+ in WINDOW_MATRIX is found satisfying the condition. */
+
+ 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 /* 0 */
+
+ /* Prepare ROW for display. Desired rows are cleared lazily,
+ i.e. they are only marked as to be cleared by setting their
+ enabled_p flag to zero. When a row is to be displayed, a prior
+ call to this function really clears it. */
+
+ void
+ prepare_desired_row (row)
+ struct glyph_row *row;
+ {
+ if (!row->enabled_p)
+ {
+ clear_glyph_row (row);
+ row->enabled_p = 1;
+ }
+ }
+
+
+ /* Return a hash code for glyph row ROW. */
+
+ int
+ line_hash_code (row)
+ struct glyph_row *row;
+ {
+ int hash = 0;
+
+ if (row->enabled_p)
+ {
+ struct glyph *glyph = row->glyphs[TEXT_AREA];
+ struct glyph *end = glyph + row->used[TEXT_AREA];
+
+ while (glyph < end)
+ {
+ int c = glyph->u.ch;
+ int face_id = glyph->face_id;
+ if (must_write_spaces)
+ c -= SPACEGLYPH;
+ hash = (((hash << 4) + (hash >> 24)) & 0x0fffffff) + c;
+ hash = (((hash << 4) + (hash >> 24)) & 0x0fffffff) + face_id;
+ ++glyph;
+ }
+
+ if (hash == 0)
+ hash = 1;
+ }
+
+ return hash;
+ }
+
+
+ /* Return the cost of drawing line VPOS in MATRIX. The cost equals
+ the number of characters in the line. If must_write_spaces is
+ zero, leading and trailing spaces are ignored. */
+
+ 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;
+
+ /* Ignore trailing and leading spaces if we can. */
+ if (!must_write_spaces)
+ {
+ /* Skip from the end over trailing spaces. */
+ while (end > beg && CHAR_GLYPH_SPACE_P (*(end - 1)))
+ --end;
+
+ /* All blank line. */
+ if (end == beg)
+ return 0;
+
+ /* Skip over leading spaces. */
+ while (CHAR_GLYPH_SPACE_P (*beg))
+ ++beg;
+ }
+
+ /* If we don't have a glyph-table, each glyph is one character,
+ so return the number of glyphs. */
+ if (glyph_table_base == 0)
+ len = end - beg;
+ else
+ {
+ /* Otherwise, scan the glyphs and accumulate their total length
+ in LEN. */
+ 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;
+ }
+
+
+ /* Test two glyph rows A and B for equality. Value is non-zero if A
+ and B have equal contents. W is the window to which the glyphs
+ rows A and B belong. It is needed here to test for partial row
+ visibility. MOUSE_FACE_P non-zero means compare the mouse_face_p
+ flags of A and B, too. */
+
+ 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;
+
+ /* Compare glyphs. */
+ 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->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))
+ /* Different partially visible characters on left margin. */
+ || a->x != b->x
+ /* Different height. */
+ || 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;
+ }
+
+
+
+ /***********************************************************************
+ Glyph Pool
+
+ See dispextern.h for an overall explanation of glyph pools.
+ ***********************************************************************/
+
+ /* Allocate a glyph_pool structure. The structure returned is
+ initialized with zeros. The global variable glyph_pool_count is
+ incremented for each pool allocated. */
+
+ static struct glyph_pool *
+ new_glyph_pool ()
+ {
+ struct glyph_pool *result;
+
+ /* Allocate a new glyph_pool and clear it. */
+ result = (struct glyph_pool *) xmalloc (sizeof *result);
+ bzero (result, sizeof *result);
+
+ /* For memory leak and double deletion checking. */
+ ++glyph_pool_count;
+
+ return result;
+ }
+
+
+ /* Free a glyph_pool structure POOL. The function may be called with
+ a null POOL pointer. The global variable glyph_pool_count is
+ decremented with every pool structure freed. If this count gets
+ negative, more structures were freed than allocated, i.e. one
+ structure must have been freed more than once or a bogus pointer
+ was passed to free_glyph_pool. */
+
+ static void
+ free_glyph_pool (pool)
+ struct glyph_pool *pool;
+ {
+ if (pool)
+ {
+ /* More freed than allocated? */
+ --glyph_pool_count;
+ xassert (glyph_pool_count >= 0);
+
+ xfree (pool->glyphs);
+ xfree (pool);
+ }
+ }
+
+
+ /* Enlarge a glyph pool POOL. MATRIX_DIM gives the number of rows and
+ columns we need. This function never shrinks a pool. The only
+ case in which this would make sense, would be when a frame's size
+ is changed from a large value to a smaller one. But, if someone
+ does it once, we can expect that he will do it again.
+
+ Value is non-zero if the pool changed in a way which makes
+ re-adjusting window glyph matrices necessary. */
+
+ 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);
+
+ /* Enlarge the glyph pool. */
+ 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;
+ }
+
+ /* Remember the number of rows and columns because (a) we use them
+ to do sanity checks, and (b) the number of columns determines
+ where rows in the frame matrix start---this must be available to
+ determine pointers to rows of window sub-matrices. */
+ pool->nrows = matrix_dim.height;
+ pool->ncolumns = matrix_dim.width;
+
+ return changed_p;
+ }
+
+
+
+ /***********************************************************************
+ Debug Code
+ ***********************************************************************/
+
+ #if GLYPH_DEBUG
+
+
+ /* Flush standard output. This is sometimes useful to call from
+ the debugger. */
+
+ void
+ flush_stdout ()
+ {
+ fflush (stdout);
+ }
+
+
+ /* Check that no glyph pointers have been lost in MATRIX. If a
+ pointer has been lost, e.g. by using a structure assignment between
+ rows, at least one pointer must occur more than once in the rows of
+ MATRIX. */
+
+ 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]));
+ }
+
+
+ /* Get a pointer to glyph row ROW in MATRIX, with bounds checks. */
+
+ struct glyph_row *
+ matrix_row (matrix, row)
+ struct glyph_matrix *matrix;
+ int row;
+ {
+ xassert (matrix && matrix->rows);
+ xassert (row >= 0 && row < matrix->nrows);
+
+ /* That's really too slow for normal testing because this function
+ is called almost everywhere. Although---it's still astonishingly
+ fast, so it is valuable to have for debugging purposes. */
+ #if 0
+ check_matrix_pointer_lossage (matrix);
+ #endif
+
+ return matrix->rows + row;
+ }
+
+
+ #if 0 /* This function makes invalid assumptions when text is
+ partially invisible. But it might come handy for debugging
+ nevertheless. */
+
+ /* Check invariants that must hold for an up to date current matrix of
+ window W. */
+
+ 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;
+
+ /* This can sometimes happen for a fresh window. */
+ if (matrix->nrows < 2)
+ return;
+
+ set_buffer_temp (buffer);
+
+ /* Note: last row is always reserved for the mode line. */
+ 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;
+
+ /* Check that character and byte positions are in sync. */
+ xassert (MATRIX_ROW_START_BYTEPOS (row)
+ == CHAR_TO_BYTE (MATRIX_ROW_START_CHARPOS (row)));
+
+ /* CHAR_TO_BYTE aborts when invoked for a position > Z. We can
+ have such a position temporarily in case of a minibuffer
+ displaying something like `[Sole completion]' at its end. */
+ if (MATRIX_ROW_END_CHARPOS (row) < BUF_ZV (current_buffer))
+ xassert (MATRIX_ROW_END_BYTEPOS (row)
+ == CHAR_TO_BYTE (MATRIX_ROW_END_CHARPOS (row)));
+
+ /* Check that end position of `row' is equal to start position
+ of next 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 /* 0 */
+
+ #endif /* GLYPH_DEBUG != 0 */
+
+
+
+ /**********************************************************************
+ Allocating/ Adjusting Glyph Matrices
+ **********************************************************************/
+
+ /* Allocate glyph matrices over a window tree for a frame-based
+ redisplay
+
+ X and Y are column/row within the frame glyph matrix where
+ sub-matrices for the window tree rooted at WINDOW must be
+ allocated. CH_DIM contains the dimensions of the smallest
+ character that could be used during display. DIM_ONLY_P non-zero
+ means that the caller of this function is only interested in the
+ result matrix dimension, and matrix adjustments should not be
+ performed.
+
+ The function returns the total width/height of the sub-matrices of
+ the window tree. If called on a frame root window, the computation
+ will take the mini-buffer window into account.
+
+ *WINDOW_CHANGE_FLAGS is set to a bit mask with bits
+
+ NEW_LEAF_MATRIX set if any window in the tree did not have a
+ glyph matrices yet, and
+
+ CHANGED_LEAF_MATRIX set if the dimension or location of a matrix of
+ any window in the tree will be changed or have been changed (see
+ DIM_ONLY_P)
+
+ *WINDOW_CHANGE_FLAGS must be initialized by the caller of this
+ function.
+
+ Windows are arranged into chains of windows on the same level
+ through the next fields of window structures. Such a level can be
+ either a sequence of horizontally adjacent windows from left to
+ right, or a sequence of vertically adjacent windows from top to
+ bottom. Each window in a horizontal sequence can be either a leaf
+ window or a vertical sequence; a window in a vertical sequence can
+ be either a leaf or a horizontal sequence. All windows in a
+ horizontal sequence have the same height, and all windows in a
+ vertical sequence have the same width.
+
+ This function uses, for historical reasons, a more general
+ algorithm to determine glyph matrix dimensions that would be
+ necessary.
+
+ The matrix height of a horizontal sequence is determined by the
+ maximum height of any matrix in the sequence. The matrix width of
+ a horizontal sequence is computed by adding up matrix widths of
+ windows in the sequence.
+
+ |<------- result width ------->|
+ +---------+----------+---------+ ---
+ | | | | |
+ | | | |
+ +---------+ | | result height
+ | +---------+
+ | | |
+ +----------+ ---
+
+ The matrix width of a vertical sequence is the maximum matrix width
+ of any window in the sequence. Its height is computed by adding up
+ matrix heights of windows in the sequence.
+
+ |<---- result width -->|
+ +---------+ ---
+ | | |
+ | | |
+ +---------+--+ |
+ | | |
+ | | result height
+ | |
+ +------------+---------+ |
+ | | |
+ | | |
+ +------------+---------+ --- */
+
+ /* Bit indicating that a new matrix will be allocated or has been
+ allocated. */
+
+ #define NEW_LEAF_MATRIX (1 << 0)
+
+ /* Bit indicating that a matrix will or has changed its location or
+ size. */
+
+ #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;
+
+ /* What combination is WINDOW part of? Compute this once since the
+ result is the same for all windows in the `next' chain. The
+ special case of a root window (parent equal to nil) is treated
+ like a vertical combination because a root window's `next'
+ points to the mini-buffer window, if any, which is arranged
+ vertically below other windows. */
+ in_horz_combination_p
+ = (!NILP (XWINDOW (window)->parent)
+ && !NILP (XWINDOW (XWINDOW (window)->parent)->hchild));
+
+ /* For WINDOW and all windows on the same level. */
+ do
+ {
+ w = XWINDOW (window);
+
+ /* Get the dimension of the window sub-matrix for W, depending
+ on whether this is a combination or a leaf 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 not already done, allocate sub-matrix structures. */
+ 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;
+ }
+
+ /* Width and height MUST be chosen so that there are no
+ holes in the frame matrix. */
+ dim.width = required_matrix_width (w);
+ dim.height = required_matrix_height (w);
+
+ /* Will matrix be re-allocated? */
+ 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_cols)
+ != w->desired_matrix->left_margin_glyphs)
+ || (margin_glyphs_to_reserve (w, dim.width,
+ w->left_margin_cols)
+ != w->desired_matrix->right_margin_glyphs))
+ *window_change_flags |= CHANGED_LEAF_MATRIX;
+
+ /* Actually change matrices, if allowed. Do not consider
+ CHANGED_LEAF_MATRIX computed above here because the pool
+ may have been changed which we don't now here. We trust
+ that we only will be called with DIM_ONLY_P != 0 when
+ necessary. */
+ 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 we are part of a horizontal combination, advance x for
+ windows to the right of W; otherwise advance y for windows
+ below W. */
+ if (in_horz_combination_p)
+ x += dim.width;
+ else
+ y += dim.height;
+
+ /* Remember maximum glyph matrix dimensions. */
+ wmax = max (wmax, dim.width);
+ hmax = max (hmax, dim.height);
+
+ /* Next window on same level. */
+ window = w->next;
+ }
+ while (!NILP (window));
+
+ /* Set `total' to the total glyph matrix dimension of this window
+ level. In a vertical combination, the width is the width of the
+ widest window; the height is the y we finally reached, corrected
+ by the y we started with. In a horizontal combination, the total
+ height is the height of the tallest window, and the width is the
+ x we finally reached, corrected by the x we started with. */
+ if (in_horz_combination_p)
+ {
+ total.width = x - x0;
+ total.height = hmax;
+ }
+ else
+ {
+ total.width = wmax;
+ total.height = y - y0;
+ }
+
+ return total;
+ }
+
+
+ /* Return the required height of glyph matrices for window W. */
+
+ 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)
+ /* One partially visible line at the top and
+ bottom of the window. */
+ + 2
+ /* 2 for header and mode line. */
+ + 2);
+ }
+ #endif /* HAVE_WINDOW_SYSTEM */
+
+ return WINDOW_TOTAL_LINES (w);
+ }
+
+
+ /* Return the required width of glyph matrices for window W. */
+
+ int
+ required_matrix_width (w)
+ struct window *w;
+ {
+ #ifdef HAVE_WINDOW_SYSTEM
+ struct frame *f = XFRAME (w->frame);
+ if (FRAME_WINDOW_P (f))
+ {
+ int ch_width = FRAME_SMALLEST_CHAR_WIDTH (f);
+ int window_pixel_width = WINDOW_TOTAL_WIDTH (w);
+
+ /* Compute number of glyphs needed in a glyph row. */
+ return (((window_pixel_width + ch_width - 1)
+ / ch_width)
+ /* 2 partially visible columns in the text area. */
+ + 2
+ /* One partially visible column at the right
+ edge of each marginal area. */
+ + 1 + 1);
+ }
+ #endif /* HAVE_WINDOW_SYSTEM */
+
+ return XINT (w->total_cols);
+ }
+
+
+ /* Allocate window matrices for window-based redisplay. W is the
+ window whose matrices must be allocated/reallocated. CH_DIM is the
+ size of the smallest character that could potentially be used on W. */
+
+ 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
+ {
+ /* W is a leaf window. */
+ struct dim dim;
+
+ /* If matrices are not yet allocated, allocate them now. */
+ 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);
+ }
+ }
+
+
+ /* Re-allocate/ re-compute glyph matrices on frame F. If F is null,
+ do it for all frames; otherwise do it just for the given frame.
+ This function must be called when a new frame is created, its size
+ changes, or its window configuration changes. */
+
+ void
+ adjust_glyphs (f)
+ struct frame *f;
+ {
+ /* Block input so that expose events and other events that access
+ glyph matrices are not processed while we are changing them. */
+ 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;
+ }
+
+
+ /* Adjust frame glyphs when Emacs is initialized.
+
+ To be called from init_display.
+
+ We need a glyph matrix because redraw will happen soon.
+ Unfortunately, window sizes on selected_frame are not yet set to
+ meaningful values. I believe we can assume that there are only two
+ windows on the frame---the mini-buffer and the root window. Frame
+ height and width seem to be correct so far. So, set the sizes of
+ windows to estimated values. */
+
+ static void
+ adjust_frame_glyphs_initially ()
+ {
+ struct frame *sf = SELECTED_FRAME ();
+ struct window *root = XWINDOW (sf->root_window);
+ struct window *mini = XWINDOW (root->next);
+ int frame_lines = FRAME_LINES (sf);
+ int frame_cols = FRAME_COLS (sf);
+ int top_margin = FRAME_TOP_MARGIN (sf);
+
+ /* Do it for the root window. */
+ XSETFASTINT (root->top_line, top_margin);
+ XSETFASTINT (root->total_cols, frame_cols);
+ set_window_height (sf->root_window, frame_lines - 1 - top_margin, 0);
+
+ /* Do it for the mini-buffer window. */
+ XSETFASTINT (mini->top_line, frame_lines - 1);
+ XSETFASTINT (mini->total_cols, frame_cols);
+ set_window_height (root->next, 1, 0);
+
+ adjust_frame_glyphs (sf);
+ glyphs_initialized_initially_p = 1;
+ }
+
+
+ /* Allocate/reallocate glyph matrices of a single frame F. */
+
+ 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);
+
+ /* Don't forget the message buffer and the buffer for
+ decode_mode_spec. */
+ adjust_frame_message_buffer (f);
+ adjust_decode_mode_spec_buffer (f);
+
+ f->glyphs_initialized_p = 1;
+ }
+
+
+ /* In the window tree with root W, build current matrices of leaf
+ windows from the frame's current matrix. */
+
+ static void
+ fake_current_matrices (window)
+ Lisp_Object window;
+ {
+ struct window *w;
+
+ for (; !NILP (window); window = w->next)
+ {
+ w = XWINDOW (window);
+
+ if (!NILP (w->hchild))
+ fake_current_matrices (w->hchild);
+ else if (!NILP (w->vchild))
+ fake_current_matrices (w->vchild);
+ else
+ {
+ int i;
+ struct frame *f = XFRAME (w->frame);
+ struct glyph_matrix *m = w->current_matrix;
+ struct glyph_matrix *fm = f->current_matrix;
+
+ xassert (m->matrix_h == WINDOW_TOTAL_LINES (w));
+ xassert (m->matrix_w == WINDOW_TOTAL_COLS (w));
+
+ for (i = 0; i < m->matrix_h; ++i)
+ {
+ struct glyph_row *r = m->rows + i;
+ struct glyph_row *fr = fm->rows + i + WINDOW_TOP_EDGE_LINE (w);
+
+ xassert (r->glyphs[TEXT_AREA] >= fr->glyphs[TEXT_AREA]
+ && r->glyphs[LAST_AREA] <= fr->glyphs[LAST_AREA]);
+
+ r->enabled_p = fr->enabled_p;
+ if (r->enabled_p)
+ {
+ r->used[LEFT_MARGIN_AREA] = m->left_margin_glyphs;
+ r->used[RIGHT_MARGIN_AREA] = m->right_margin_glyphs;
+ r->used[TEXT_AREA] = (m->matrix_w
+ - r->used[LEFT_MARGIN_AREA]
+ - r->used[RIGHT_MARGIN_AREA]);
+ r->mode_line_p = 0;
+ }
+ }
+ }
+ }
+ }
+
+
+ /* Save away the contents of frame F's current frame matrix. Value is
+ a glyph matrix holding the contents of F's current frame matrix. */
+
+ 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;
+ }
+
+
+ /* Restore the contents of frame F's current frame matrix from SAVED,
+ and free memory associated with 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);
+ }
+
+
+
+ /* Allocate/reallocate glyph matrices of a single frame F for
+ frame-based redisplay. */
+
+ 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;
+
+ /* Determine the smallest character in any font for F. On
+ console windows, all characters have dimension (1, 1). */
+ ch_dim.width = ch_dim.height = 1;
+
+ top_window_y = FRAME_TOP_MARGIN (f);
+
+ /* Allocate glyph pool structures if not already done. */
+ if (f->desired_pool == NULL)
+ {
+ f->desired_pool = new_glyph_pool ();
+ f->current_pool = new_glyph_pool ();
+ }
+
+ /* Allocate frames matrix structures if needed. */
+ if (f->desired_matrix == NULL)
+ {
+ f->desired_matrix = new_glyph_matrix (f->desired_pool);
+ f->current_matrix = new_glyph_matrix (f->current_pool);
+ }
+
+ /* Compute window glyph matrices. (This takes the mini-buffer
+ window into account). The result is the size of the frame glyph
+ matrix needed. The variable window_change_flags is set to a bit
+ mask indicating whether new matrices will be allocated or
+ existing matrices change their size or location within the frame
+ matrix. */
+ window_change_flags = 0;
+ matrix_dim
+ = allocate_matrices_for_frame_redisplay (FRAME_ROOT_WINDOW (f),
+ 0, top_window_y,
+ 1,
+ &window_change_flags);
+
+ /* Add in menu bar lines, if any. */
+ matrix_dim.height += top_window_y;
+
+ /* Enlarge pools as necessary. */
+ pool_changed_p = realloc_glyph_pool (f->desired_pool, matrix_dim);
+ realloc_glyph_pool (f->current_pool, matrix_dim);
+
+ /* Set up glyph pointers within window matrices. Do this only if
+ absolutely necessary since it requires a frame redraw. */
+ if (pool_changed_p || window_change_flags)
+ {
+ /* Do it for window matrices. */
+ allocate_matrices_for_frame_redisplay (FRAME_ROOT_WINDOW (f),
+ 0, top_window_y, 0,
+ &window_change_flags);
+
+ /* Size of frame matrices must equal size of frame. Note
+ that we are called for X frames with window widths NOT equal
+ to the frame width (from CHANGE_FRAME_SIZE_1). */
+ xassert (matrix_dim.width == FRAME_COLS (f)
+ && matrix_dim.height == FRAME_LINES (f));
+
+ /* Pointers to glyph memory in glyph rows are exchanged during
+ the update phase of redisplay, which means in general that a
+ frame's current matrix consists of pointers into both the
+ desired and current glyph pool of the frame. Adjusting a
+ matrix sets the frame matrix up so that pointers are all into
+ the same pool. If we want to preserve glyph contents of the
+ current matrix over a call to adjust_glyph_matrix, we must
+ make a copy of the current glyphs, and restore the current
+ matrix' contents from that copy. */
+ 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);
+ }
+ }
+ }
+
+
+ /* Allocate/reallocate glyph matrices of a single frame F for
+ window-based redisplay. */
+
+ 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));
+
+ /* Get minimum sizes. */
+ #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/reallocate window matrices. */
+ allocate_matrices_for_window_redisplay (XWINDOW (FRAME_ROOT_WINDOW (f)));
+
+ /* Allocate/ reallocate matrices of the dummy window used to display
+ the menu bar under X when no X toolkit support is available. */
+ #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
+ {
+ /* Allocate a dummy window if not already done. */
+ 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);
+
+ /* Set window dimensions to frame dimensions and allocate or
+ adjust glyph matrices of W. */
+ XSETFASTINT (w->top_line, 0);
+ XSETFASTINT (w->left_col, 0);
+ XSETFASTINT (w->total_lines, FRAME_MENU_BAR_LINES (f));
+ XSETFASTINT (w->total_cols, FRAME_TOTAL_COLS (f));
+ allocate_matrices_for_window_redisplay (w);
+ }
+ #endif /* not USE_X_TOOLKIT */
+
+ #ifndef USE_GTK
+ /* Allocate/ reallocate matrices of the tool bar window. If we
+ don't have a tool bar window yet, make one. */
+ if (NILP (f->tool_bar_window))
+ {
+ f->tool_bar_window = make_window ();
+ w = XWINDOW (f->tool_bar_window);
+ XSETFRAME (w->frame, f);
+ w->pseudo_window_p = 1;
+ }
+ else
+ w = XWINDOW (f->tool_bar_window);
+
+ XSETFASTINT (w->top_line, FRAME_MENU_BAR_LINES (f));
+ XSETFASTINT (w->left_col, 0);
+ XSETFASTINT (w->total_lines, FRAME_TOOL_BAR_LINES (f));
+ XSETFASTINT (w->total_cols, FRAME_TOTAL_COLS (f));
+ allocate_matrices_for_window_redisplay (w);
+ #endif
+ }
+
+
+ /* Adjust/ allocate message buffer of frame F.
+
+ Note that the message buffer is never freed. Since I could not
+ find a free in 19.34, I assume that freeing it would be
+ problematic in some way and don't do it either.
+
+ (Implementation note: It should be checked if we can free it
+ eventually without causing trouble). */
+
+ 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);
+ }
+
+
+ /* Re-allocate buffer for decode_mode_spec on frame F. */
+
+ 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);
+ }
+
+
+
+ /**********************************************************************
+ Freeing Glyph Matrices
+ **********************************************************************/
+
+ /* Free glyph memory for a frame F. F may be null. This function can
+ be called for the same frame more than once. The root window of
+ F may be nil when this function is called. This is the case when
+ the function is called when F is destroyed. */
+
+ void
+ free_glyphs (f)
+ struct frame *f;
+ {
+ if (f && f->glyphs_initialized_p)
+ {
+ /* Block interrupt input so that we don't get surprised by an X
+ event while we're in an inconsistent state. */
+ BLOCK_INPUT;
+ f->glyphs_initialized_p = 0;
+
+ /* Release window sub-matrices. */
+ if (!NILP (f->root_window))
+ free_window_matrices (XWINDOW (f->root_window));
+
+ /* Free the dummy window for menu bars without X toolkit and its
+ glyph matrices. */
+ 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;
+ }
+
+ /* Free the tool bar window and its glyph matrices. */
+ 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;
+ }
+
+ /* Release frame glyph matrices. Reset fields to zero in
+ case we are called a second time. */
+ if (f->desired_matrix)
+ {
+ free_glyph_matrix (f->desired_matrix);
+ free_glyph_matrix (f->current_matrix);
+ f->desired_matrix = f->current_matrix = NULL;
+ }
+
+ /* Release glyph pools. */
+ 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;
+ }
+ }
+
+
+ /* Free glyph sub-matrices in the window tree rooted at W. This
+ function may be called with a null pointer, and it may be called on
+ the same tree more than once. */
+
+ 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
+ {
+ /* This is a leaf window. Free its memory and reset fields
+ to zero in case this function is called a second time for
+ W. */
+ free_glyph_matrix (w->current_matrix);
+ free_glyph_matrix (w->desired_matrix);
+ w->current_matrix = w->desired_matrix = NULL;
+ }
+
+ /* Next window on same level. */
+ w = NILP (w->next) ? 0 : XWINDOW (w->next);
+ }
+ }
+
+
+ /* Check glyph memory leaks. This function is called from
+ shut_down_emacs. Note that frames are not destroyed when Emacs
+ exits. We therefore free all glyph memory for all active frames
+ explicitly and check that nothing is left allocated. */
+
+ void
+ check_glyph_memory ()
+ {
+ Lisp_Object tail, frame;
+
+ /* Free glyph memory for all frames. */
+ FOR_EACH_FRAME (tail, frame)
+ free_glyphs (XFRAME (frame));
+
+ /* Check that nothing is left allocated. */
+ if (glyph_matrix_count)
+ abort ();
+ if (glyph_pool_count)
+ abort ();
+ }
+
+
+
+ /**********************************************************************
+ Building a Frame Matrix
+ **********************************************************************/
+
+ /* Most of the redisplay code works on glyph matrices attached to
+ windows. This is a good solution most of the time, but it is not
+ suitable for terminal code. Terminal output functions cannot rely
+ on being able to set an arbitrary terminal window. Instead they
+ must be provided with a view of the whole frame, i.e. the whole
+ screen. We build such a view by constructing a frame matrix from
+ window matrices in this section.
+
+ Windows that must be updated have their must_be_update_p flag set.
+ For all such windows, their desired matrix is made part of the
+ desired frame matrix. For other windows, their current matrix is
+ made part of the desired frame matrix.
+
+ +-----------------+----------------+
+ | desired | desired |
+ | | |
+ +-----------------+----------------+
+ | current |
+ | |
+ +----------------------------------+
+
+ Desired window matrices can be made part of the frame matrix in a
+ cheap way: We exploit the fact that the desired frame matrix and
+ desired window matrices share their glyph memory. This is not
+ possible for current window matrices. Their glyphs are copied to
+ the desired frame matrix. The latter is equivalent to
+ preserve_other_columns in the old redisplay.
+
+ Used glyphs counters for frame matrix rows are the result of adding
+ up glyph lengths of the window matrices. A line in the frame
+ matrix is enabled, if a corresponding line in a window matrix is
+ enabled.
+
+ After building the desired frame matrix, it will be passed to
+ terminal code, which will manipulate both the desired and current
+ frame matrix. Changes applied to the frame's current matrix have
+ to be visible in current window matrices afterwards, of course.
+
+ This problem is solved like this:
+
+ 1. Window and frame matrices share glyphs. Window matrices are
+ constructed in a way that their glyph contents ARE the glyph
+ contents needed in a frame matrix. Thus, any modification of
+ glyphs done in terminal code will be reflected in window matrices
+ automatically.
+
+ 2. Exchanges of rows in a frame matrix done by terminal code are
+ intercepted by hook functions so that corresponding row operations
+ on window matrices can be performed. This is necessary because we
+ use pointers to glyphs in glyph row structures. To satisfy the
+ assumption of point 1 above that glyphs are updated implicitly in
+ window matrices when they are manipulated via the frame matrix,
+ window and frame matrix must of course agree where to find the
+ glyphs for their rows. Possible manipulations that must be
+ mirrored are assignments of rows of the desired frame matrix to the
+ current frame matrix and scrolling the current frame matrix. */
+
+ /* Build frame F's desired matrix from window matrices. Only windows
+ which have the flag must_be_updated_p set have to be updated. Menu
+ bar lines of a frame are not covered by window matrices, so make
+ sure not to touch them in this function. */
+
+ static void
+ build_frame_matrix (f)
+ struct frame *f;
+ {
+ int i;
+
+ /* F must have a frame matrix when this function is called. */
+ xassert (!FRAME_WINDOW_P (f));
+
+ /* Clear all rows in the frame matrix covered by window matrices.
+ Menu bar lines are not covered by windows. */
+ for (i = FRAME_TOP_MARGIN (f); i < f->desired_matrix->nrows; ++i)
+ clear_glyph_row (MATRIX_ROW (f->desired_matrix, i));
+
+ /* Build the matrix by walking the window tree. */
+ build_frame_matrix_from_window_tree (f->desired_matrix,
+ XWINDOW (FRAME_ROOT_WINDOW (f)));
+ }
+
+
+ /* Walk a window tree, building a frame matrix MATRIX from window
+ matrices. W is the root of a window tree. */
+
+ 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);
+ }
+ }
+
+
+ /* Add a window's matrix to a frame matrix. FRAME_MATRIX is the
+ desired frame matrix built. W is a leaf window whose desired or
+ current matrix is to be added to FRAME_MATRIX. W's flag
+ must_be_updated_p determines which matrix it contributes to
+ FRAME_MATRIX. If must_be_updated_p is non-zero, W's desired matrix
+ is added to FRAME_MATRIX, otherwise W's current matrix is added.
+ Adding a desired matrix means setting up used counters and such in
+ frame rows, while adding a current window matrix to FRAME_MATRIX
+ means copying glyphs. The latter case corresponds to
+ preserve_other_columns in the old redisplay. */
+
+ 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;
+ /* If non-zero, a glyph to insert at the right border of W. */
+ GLYPH right_border_glyph = 0;
+
+ /* Set window_matrix to the matrix we have to add to FRAME_MATRIX. */
+ if (w->must_be_updated_p)
+ {
+ window_matrix = w->desired_matrix;
+
+ /* Decide whether we want to add a vertical border glyph. */
+ 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;
+
+ /* For all rows in the window matrix and corresponding rows in the
+ frame 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 the frame row with spaces up to the left margin of the
+ window row. */
+ fill_up_frame_row_with_spaces (frame_row, window_matrix->matrix_x);
+
+ /* Fill up areas in the window matrix row with spaces. */
+ fill_up_glyph_row_with_spaces (window_row);
+
+ /* If only part of W's desired matrix has been built, and
+ window_row wasn't displayed, use the corresponding current
+ row instead. */
+ 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)
+ {
+ /* Copy window row to frame row. */
+ 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);
+
+ /* Only when a desired row has been displayed, we want
+ the corresponding frame row to be updated. */
+ frame_row->enabled_p = 1;
+
+ /* Maybe insert a vertical border between horizontally adjacent
+ windows. */
+ if (right_border_glyph)
+ {
+ struct glyph *border = window_row->glyphs[LAST_AREA] - 1;
+ SET_CHAR_GLYPH_FROM_GLYPH (*border, right_border_glyph);
+ }
+
+ /* Window row window_y must be a slice of frame row
+ frame_y. */
+ xassert (glyph_row_slice_p (window_row, frame_row));
+
+ /* If rows are in sync, we don't have to copy glyphs because
+ frame and window share glyphs. */
+
+ #if GLYPH_DEBUG
+ strcpy (w->current_matrix->method, w->desired_matrix->method);
+ add_window_display_history (w, w->current_matrix->method, 0);
+ #endif
+ }
+
+ /* Set number of used glyphs in the frame matrix. Since we fill
+ up with spaces, and visit leaf windows from left to right it
+ can be done simply. */
+ frame_row->used[TEXT_AREA]
+ = window_matrix->matrix_x + window_matrix->matrix_w;
+
+ /* Next row. */
+ ++window_y;
+ ++frame_y;
+ }
+ }
+
+
+ /* Add spaces to a glyph row ROW in a window matrix.
+
+ Each row has the form:
+
+ +---------+-----------------------------+------------+
+ | left | text | right |
+ +---------+-----------------------------+------------+
+
+ Left and right marginal areas are optional. This function adds
+ spaces to areas so that there are no empty holes between areas.
+ In other words: If the right area is not empty, the text area
+ is filled up with spaces up to the right area. If the text area
+ is not empty, the left area is filled up.
+
+ To be called for frame-based redisplay, only. */
+
+ 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);
+ }
+
+
+ /* Fill area AREA of glyph row ROW with spaces. To be called for
+ frame-based redisplay only. */
+
+ 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];
+ }
+ }
+
+
+ /* Add spaces to the end of ROW in a frame matrix until index UPTO is
+ reached. In frame matrices only one area, TEXT_AREA, is used. */
+
+ 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;
+ }
+
+
+
+ /**********************************************************************
+ Mirroring operations on frame matrices in window matrices
+ **********************************************************************/
+
+ /* Set frame being updated via frame-based redisplay to F. This
+ function must be called before updates to make explicit that we are
+ working on frame matrices or not. */
+
+ static INLINE void
+ set_frame_matrix_frame (f)
+ struct frame *f;
+ {
+ frame_matrix_frame = f;
+ }
+
+
+ /* Make sure glyph row ROW in CURRENT_MATRIX is up to date.
+ DESIRED_MATRIX is the desired matrix corresponding to
+ CURRENT_MATRIX. The update is done by exchanging glyph pointers
+ between rows in CURRENT_MATRIX and DESIRED_MATRIX. If
+ frame_matrix_frame is non-null, this indicates that the exchange is
+ done in frame matrices, and that we have to perform analogous
+ operations in window matrices of frame_matrix_frame. */
+
+ 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;
+
+ /* Do current_row = desired_row. This exchanges glyph pointers
+ between both rows, and does a structure assignment otherwise. */
+ assign_row (current_row, desired_row);
+
+ /* Enable current_row to mark it as valid. */
+ current_row->enabled_p = 1;
+ current_row->mouse_face_p = mouse_face_p;
+
+ /* If we are called on frame matrices, perform analogous operations
+ for window matrices. */
+ if (frame_matrix_frame)
+ mirror_make_current (XWINDOW (frame_matrix_frame->root_window), row);
+ }
+
+
+ /* W is the root of a window tree. FRAME_ROW is the index of a row in
+ W's frame which has been made current (by swapping pointers between
+ current and desired matrix). Perform analogous operations in the
+ matrices of leaf windows in the window tree rooted at W. */
+
+ 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
+ {
+ /* Row relative to window W. Don't use FRAME_TO_WINDOW_VPOS
+ here because the checks performed in debug mode there
+ will not allow the conversion. */
+ int row = frame_row - w->desired_matrix->matrix_y;
+
+ /* If FRAME_ROW is within W, assign the desired row to the
+ current row (exchanging glyph pointers). */
+ 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);
+ }
+ }
+
+
+ /* Perform row dance after scrolling. We are working on the range of
+ lines UNCHANGED_AT_TOP + 1 to UNCHANGED_AT_TOP + NLINES (not
+ including) in MATRIX. COPY_FROM is a vector containing, for each
+ row I in the range 0 <= I < NLINES, the index of the original line
+ to move to I. This index is relative to the row range, i.e. 0 <=
+ index < NLINES. RETAINED_P is a vector containing zero for each
+ row 0 <= I < NLINES which is empty.
+
+ This function is called from do_scrolling and do_direct_scrolling. */
+
+ 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;
+ {
+ /* A copy of original rows. */
+ struct glyph_row *old_rows;
+
+ /* Rows to assign to. */
+ struct glyph_row *new_rows = MATRIX_ROW (matrix, unchanged_at_top);
+
+ int i;
+
+ /* Make a copy of the original rows. */
+ old_rows = (struct glyph_row *) alloca (nlines * sizeof *old_rows);
+ bcopy (new_rows, old_rows, nlines * sizeof *old_rows);
+
+ /* Assign new rows, maybe clear lines. */
+ 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;
+
+ /* RETAINED_P is zero for empty lines. */
+ if (!retained_p[copy_from[i]])
+ new_rows[i].enabled_p = 0;
+ }
+
+ /* Do the same for window matrices, if MATRIX is a frame matrix. */
+ if (frame_matrix_frame)
+ mirror_line_dance (XWINDOW (frame_matrix_frame->root_window),
+ unchanged_at_top, nlines, copy_from, retained_p);
+ }
+
+
+ /* Synchronize glyph pointers in the current matrix of window W with
+ the current frame matrix. */
+
+ static void
+ sync_window_with_frame_matrix_rows (w)
+ struct window *w;
+ {
+ struct frame *f = XFRAME (w->frame);
+ struct glyph_row *window_row, *window_row_end, *frame_row;
+ int left, right, x, width;
+
+ /* Preconditions: W must be a leaf window on a tty frame. */
+ xassert (NILP (w->hchild) && NILP (w->vchild));
+ xassert (!FRAME_WINDOW_P (f));
+
+ left = margin_glyphs_to_reserve (w, 1, w->left_margin_cols);
+ right = margin_glyphs_to_reserve (w, 1, w->right_margin_cols);
+ x = w->current_matrix->matrix_x;
+ width = w->current_matrix->matrix_w;
+
+ window_row = w->current_matrix->rows;
+ window_row_end = window_row + w->current_matrix->nrows;
+ frame_row = f->current_matrix->rows + WINDOW_TOP_EDGE_LINE (w);
+
+ for (; window_row < window_row_end; ++window_row, ++frame_row)
+ {
+ window_row->glyphs[LEFT_MARGIN_AREA]
+ = frame_row->glyphs[0] + x;
+ window_row->glyphs[TEXT_AREA]
+ = window_row->glyphs[LEFT_MARGIN_AREA] + left;
+ window_row->glyphs[LAST_AREA]
+ = window_row->glyphs[LEFT_MARGIN_AREA] + width;
+ window_row->glyphs[RIGHT_MARGIN_AREA]
+ = window_row->glyphs[LAST_AREA] - right;
+ }
+ }
+
+
+ /* Return the window in the window tree rooted in W containing frame
+ row ROW. Value is null if none is found. */
+
+ struct window *
+ frame_row_to_window (w, row)
+ struct window *w;
+ int row;
+ {
+ struct window *found = NULL;
+
+ while (w && !found)
+ {
+ if (!NILP (w->hchild))
+ found = frame_row_to_window (XWINDOW (w->hchild), row);
+ else if (!NILP (w->vchild))
+ found = frame_row_to_window (XWINDOW (w->vchild), row);
+ else if (row >= WINDOW_TOP_EDGE_LINE (w)
+ && row < WINDOW_BOTTOM_EDGE_LINE (w))
+ found = w;
+
+ w = NILP (w->next) ? 0 : XWINDOW (w->next);
+ }
+
+ return found;
+ }
+
+
+ /* Perform a line dance in the window tree rooted at W, after
+ scrolling a frame matrix in mirrored_line_dance.
+
+ We are working on the range of lines UNCHANGED_AT_TOP + 1 to
+ UNCHANGED_AT_TOP + NLINES (not including) in W's frame matrix.
+ COPY_FROM is a vector containing, for each row I in the range 0 <=
+ I < NLINES, the index of the original line to move to I. This
+ index is relative to the row range, i.e. 0 <= index < NLINES.
+ RETAINED_P is a vector containing zero for each row 0 <= I < NLINES
+ which is empty. */
+
+ 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
+ {
+ /* W is a leaf window, and we are working on its current
+ matrix m. */
+ struct glyph_matrix *m = w->current_matrix;
+ int i, sync_p = 0;
+ struct glyph_row *old_rows;
+
+ /* Make a copy of the original rows of matrix m. */
+ 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)
+ {
+ /* Frame relative line assigned to. */
+ int frame_to = i + unchanged_at_top;
+
+ /* Frame relative line assigned. */
+ int frame_from = copy_from[i] + unchanged_at_top;
+
+ /* Window relative line assigned to. */
+ int window_to = frame_to - m->matrix_y;
+
+ /* Window relative line assigned. */
+ int window_from = frame_from - m->matrix_y;
+
+ /* Is assigned line inside window? */
+ int from_inside_window_p
+ = window_from >= 0 && window_from < m->matrix_h;
+
+ /* Is assigned to line inside window? */
+ int to_inside_window_p
+ = window_to >= 0 && window_to < m->matrix_h;
+
+ if (from_inside_window_p && to_inside_window_p)
+ {
+ /* Enabled setting before assignment. */
+ int enabled_before_p;
+
+ /* Do the assignment. The enabled_p flag is saved
+ over the assignment because the old redisplay did
+ that. */
+ 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 frame line is empty, window line is empty, too. */
+ if (!retained_p[copy_from[i]])
+ m->rows[window_to].enabled_p = 0;
+ }
+ else if (to_inside_window_p)
+ {
+ /* A copy between windows. This is an infrequent
+ case not worth optimizing. */
+ 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 frame line is empty, window line is empty, too. */
+ 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 there was a copy between windows, make sure glyph
+ pointers are in sync with the frame matrix. */
+ if (sync_p)
+ sync_window_with_frame_matrix_rows (w);
+
+ /* Check that no pointers are lost. */
+ CHECK_MATRIX (m);
+ }
+
+ /* Next window on same level. */
+ w = NILP (w->next) ? 0 : XWINDOW (w->next);
+ }
+ }
+
+
+ #if GLYPH_DEBUG
+
+ /* Check that window and frame matrices agree about their
+ understanding where glyphs of the rows are to find. For each
+ window in the window tree rooted at W, check that rows in the
+ matrices of leaf window agree with their frame matrices about
+ glyph pointers. */
+
+ 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);
+ }
+ }
+
+
+ /* Check that window rows are slices of frame rows. WINDOW_MATRIX is
+ a window and FRAME_MATRIX is the corresponding frame matrix. For
+ each row in WINDOW_MATRIX check that it's a slice of the
+ corresponding frame row. If it isn't, abort. */
+
+ static void
+ check_matrix_pointers (window_matrix, frame_matrix)
+ struct glyph_matrix *window_matrix, *frame_matrix;
+ {
+ /* Row number in WINDOW_MATRIX. */
+ int i = 0;
+
+ /* Row number corresponding to I in FRAME_MATRIX. */
+ int j = window_matrix->matrix_y;
+
+ /* For all rows check that the row in the window matrix is a
+ slice of the row in the frame matrix. If it isn't we didn't
+ mirror an operation on the frame matrix correctly. */
+ while (i < window_matrix->nrows)
+ {
+ if (!glyph_row_slice_p (window_matrix->rows + i,
+ frame_matrix->rows + j))
+ abort ();
+ ++i, ++j;
+ }
+ }
+
+ #endif /* GLYPH_DEBUG != 0 */
+
+
+
+ /**********************************************************************
+ VPOS and HPOS translations
+ **********************************************************************/
+
+ #if GLYPH_DEBUG
+
+ /* Translate vertical position VPOS which is relative to window W to a
+ vertical position relative to W's frame. */
+
+ static int
+ window_to_frame_vpos (w, vpos)
+ struct window *w;
+ int vpos;
+ {
+ struct frame *f = XFRAME (w->frame);
+
+ xassert (!FRAME_WINDOW_P (f));
+ xassert (vpos >= 0 && vpos <= w->desired_matrix->nrows);
+ vpos += WINDOW_TOP_EDGE_LINE (w);
+ xassert (vpos >= 0 && vpos <= FRAME_LINES (f));
+ return vpos;
+ }
+
+
+ /* Translate horizontal position HPOS which is relative to window W to
+ a horizontal position relative to W's frame. */
+
+ 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 += WINDOW_LEFT_EDGE_COL (w);
+ return hpos;
+ }
+
+ #endif /* GLYPH_DEBUG */
+
+
+
+ /**********************************************************************
+ Redrawing Frames
+ **********************************************************************/
+
+ DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0,
+ doc: /* Clear frame FRAME and output again what is supposed to appear
on it. */)
+ (frame)
+ Lisp_Object frame;
+ {
+ struct frame *f;
+
+ CHECK_LIVE_FRAME (frame);
+ f = XFRAME (frame);
+
+ /* Ignore redraw requests, if frame has no glyphs yet.
+ (Implementation note: It still has to be checked why we are
+ called so early here). */
+ 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 all windows as inaccurate, so that every window will have
+ its redisplay done. */
+ mark_window_display_accurate (FRAME_ROOT_WINDOW (f), 0);
+ set_window_update_flags (XWINDOW (FRAME_ROOT_WINDOW (f)), 1);
+ f->garbaged = 0;
+ return Qnil;
+ }
+
+
+ /* Redraw frame F. This is nothing more than a call to the Lisp
+ function redraw-frame. */
+
+ void
+ redraw_frame (f)
+ struct frame *f;
+ {
+ Lisp_Object frame;
+ XSETFRAME (frame, f);
+ Fredraw_frame (frame);
+ }
+
+
+ DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "",
+ doc: /* 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;
+ }
+
+
+ /* This is used when frame_garbaged is set. Call Fredraw_frame on all
+ visible frames marked as garbaged. */
+
+ 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);
+ }
+
+
+
+ /***********************************************************************
+ Direct Operations
+ ***********************************************************************/
+
+ /* Try to update display and current glyph matrix directly.
+
+ This function is called after a character G has been inserted into
+ current_buffer. It tries to update the current glyph matrix and
+ perform appropriate screen output to reflect the insertion. If it
+ succeeds, the global flag redisplay_performed_directly_p will be
+ set to 1, and thereby prevent the more costly general redisplay
+ from running (see redisplay_internal).
+
+ This function is not called for `hairy' character insertions.
+ In particular, it is not called when after or before change
+ functions exist, like they are used by font-lock. See keyboard.c
+ for details where this function is called. */
+
+ 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;
+ /* Non-null means that redisplay of W is based on window matrices. */
+ int window_redisplay_p = FRAME_WINDOW_P (f);
+ /* Non-null means we are in overwrite mode. */
+ int overwrite_p = !NILP (current_buffer->overwrite_mode);
+ int added_width;
+ struct text_pos pos;
+ int delta, delta_bytes;
+
+ /* Not done directly. */
+ redisplay_performed_directly_p = 0;
+
+ /* Quickly give up for some common cases. */
+ if (cursor_in_echo_area
+ /* Give up if fonts have changed. */
+ || fonts_changed_p
+ /* Give up if face attributes have been changed. */
+ || face_change_count
+ /* Give up if cursor position not really known. */
+ || !display_completed
+ /* Give up if buffer appears in two places. */
+ || buffer_shared > 1
+ /* Give up if currently displaying a message instead of the
+ minibuffer contents. */
+ || (EQ (selected_window, minibuf_window)
+ && EQ (minibuf_window, echo_area_window))
+ /* Give up for hscrolled mini-buffer because display of the prompt
+ is handled specially there (see display_line). */
+ || (MINI_WINDOW_P (w) && XFASTINT (w->hscroll))
+ /* Give up if overwriting in the middle of a line. */
+ || (overwrite_p
+ && PT != ZV
+ && FETCH_BYTE (PT) != '\n')
+ /* Give up for tabs and line ends. */
+ || g == '\t'
+ || g == '\n'
+ || g == '\r'
+ /* Give up if unable to display the cursor in the window. */
+ || w->cursor.vpos < 0
+ /* Give up if we are showing a message or just cleared the message
+ because we might need to resize the echo area window. */
+ || !NILP (echo_area_buffer[0])
+ || !NILP (echo_area_buffer[1])
+ || (glyph_row = MATRIX_ROW (w->current_matrix, w->cursor.vpos),
+ /* Can't do it in a continued line because continuation
+ lines would change. */
+ (glyph_row->continued_p
+ /* Can't use this method if the line overlaps others or is
+ overlapped by others because these other lines would
+ have to be redisplayed. */
+ || glyph_row->overlapping_p
+ || glyph_row->overlapped_p))
+ /* Can't do it for partial width windows on terminal frames
+ because we can't clear to eol in such a window. */
+ || (!window_redisplay_p && !WINDOW_FULL_WIDTH_P (w)))
+ return 0;
+
+ /* If we can't insert glyphs, we can use this method only
+ at the end of a line. */
+ if (!char_ins_del_ok)
+ if (PT != ZV && FETCH_BYTE (PT_BYTE) != '\n')
+ return 0;
+
+ /* Set up a display iterator structure for W. Glyphs will be
+ produced in scratch_glyph_row. Current position is W's cursor
+ position. */
+ 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;
+
+ /* Give up if highlighting trailing whitespace and we have trailing
+ whitespace in glyph_row. We would have to remove the trailing
+ whitespace face in that case. */
+ 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;
+ }
+
+ /* Give up if there are overlay strings at pos. This would fail
+ if the overlay string has newlines in it. */
+ 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);
+
+ /* More than one display element may be returned for PT - 1 if
+ (i) it's a control character which is translated into `\003' or
+ `^C', or (ii) it has a display table entry, or (iii) it's a
+ combination of both. */
+ delta = delta_bytes = 0;
+ while (get_next_display_element (&it))
+ {
+ PRODUCE_GLYPHS (&it);
+
+ /* Give up if glyph doesn't fit completely on the line. */
+ if (it.current_x >= it.last_visible_x)
+ return 0;
+
+ /* Give up if new glyph has different ascent or descent than
+ the original row, or if it is not a character glyph. */
+ 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);
+ }
+
+ /* Give up if we hit the right edge of the window. We would have
+ to insert truncation or continuation glyphs. */
+ 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;
+
+ /* Give up if there is a \t following in the line. */
+ 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);
+ }
+
+ /* Number of new glyphs produced. */
+ n = it.glyph_row->used[TEXT_AREA];
+
+ /* Start and end of glyphs in original row. */
+ glyphs = glyph_row->glyphs[TEXT_AREA] + w->cursor.hpos;
+ end = glyph_row->glyphs[1 + TEXT_AREA];
+
+ /* Make room for new glyphs, then insert them. */
+ 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]);
+
+ /* Compute new line width. */
+ 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;
+ }
+
+ /* Increment buffer positions for glyphs following the newly
+ inserted ones. */
+ 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;
+ }
+
+ /* Adjust positions in lines following the one we are in. */
+ 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);
+
+ /* Write glyphs. If at end of row, we can simply call write_glyphs.
+ In the middle, we have to insert glyphs. Note that this is now
+ implemented for X frames. The implementation uses updated_window
+ and updated_row. */
+ updated_row = glyph_row;
+ updated_area = TEXT_AREA;
+ update_begin (f);
+ if (rif)
+ {
+ rif->update_window_begin_hook (w);
+
+ if (glyphs == end - n
+ /* In front of a space added by append_space. */
+ || (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);
+
+ /* How to set the cursor differs depending on whether we are
+ using a frame matrix or a window matrix. Note that when
+ a frame matrix is used, cursor_to expects frame coordinates,
+ and the X and Y parameters are not used. */
+ if (window_redisplay_p)
+ rif->cursor_to (w->cursor.vpos, w->cursor.hpos,
+ w->cursor.y, w->cursor.x);
+ else
+ {
+ int x, y;
+ x = (WINDOW_TO_FRAME_HPOS (w, w->cursor.hpos)
+ + (INTEGERP (w->left_margin_cols)
+ ? XFASTINT (w->left_margin_cols)
+ : 0));
+ y = WINDOW_TO_FRAME_VPOS (w, w->cursor.vpos);
+ cursor_to (y, x);
+ }
+
+ if (rif)
+ rif->update_window_end_hook (w, 1, 0);
+ update_end (f);
+ updated_row = NULL;
+ fflush (stdout);
+
+ TRACE ((stderr, "direct output for insert\n"));
+ mark_window_display_accurate (it.window, 1);
+ redisplay_performed_directly_p = 1;
+ return 1;
+ }
+
+
+ /* Perform a direct display update for moving PT by N positions
+ left or right. N < 0 means a movement backwards. This function
+ is currently only called for N == 1 or N == -1. */
+
+ int
+ direct_output_forward_char (n)
+ int n;
+ {
+ struct frame *f = SELECTED_FRAME ();
+ struct window *w = XWINDOW (selected_window);
+ struct glyph_row *row;
+
+ /* Give up if point moved out of or into a composition. */
+ if (check_point_in_composition (current_buffer, XINT (w->last_point),
+ current_buffer, PT))
+ return 0;
+
+ /* Give up if face attributes have been changed. */
+ if (face_change_count)
+ return 0;
+
+ /* Give up if current matrix is not up to date or we are
+ displaying a message. */
+ if (!display_completed || cursor_in_echo_area)
+ return 0;
+
+ /* Give up if the buffer's direction is reversed. */
+ if (!NILP (XBUFFER (w->buffer)->direction_reversed))
+ return 0;
+
+ /* Can't use direct output if highlighting a region. */
+ if (!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
+ return 0;
+
+ /* Can't use direct output if highlighting trailing whitespace. */
+ if (!NILP (Vshow_trailing_whitespace))
+ return 0;
+
+ /* Give up if we are showing a message or just cleared the message
+ because we might need to resize the echo area window. */
+ if (!NILP (echo_area_buffer[0]) || !NILP (echo_area_buffer[1]))
+ return 0;
+
+ /* Give up if currently displaying a message instead of the
+ minibuffer contents. */
+ if (XWINDOW (minibuf_window) == w
+ && EQ (minibuf_window, echo_area_window))
+ return 0;
+
+ /* Give up if we don't know where the cursor is. */
+ if (w->cursor.vpos < 0)
+ return 0;
+
+ row = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
+
+ /* Give up if PT is outside of the last known cursor row. */
+ if (PT <= MATRIX_ROW_START_CHARPOS (row)
+ || PT >= MATRIX_ROW_END_CHARPOS (row))
+ return 0;
+
+ set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+
+ w->last_cursor = w->cursor;
+ XSETFASTINT (w->last_point, PT);
+
+ xassert (w->cursor.hpos >= 0
+ && w->cursor.hpos < w->desired_matrix->matrix_w);
+
+ if (FRAME_WINDOW_P (f))
+ rif->cursor_to (w->cursor.vpos, w->cursor.hpos,
+ w->cursor.y, w->cursor.x);
+ else
+ {
+ int x, y;
+ x = (WINDOW_TO_FRAME_HPOS (w, w->cursor.hpos)
+ + (INTEGERP (w->left_margin_cols)
+ ? XFASTINT (w->left_margin_cols)
+ : 0));
+ y = WINDOW_TO_FRAME_VPOS (w, w->cursor.vpos);
+ cursor_to (y, x);
+ }
+
+ fflush (stdout);
+ redisplay_performed_directly_p = 1;
+ return 1;
+ }
+
+
+
+ /***********************************************************************
+ Frame Update
+ ***********************************************************************/
+
+ /* Update frame F based on the data in desired matrices.
+
+ If FORCE_P is non-zero, don't let redisplay be stopped by detecting
+ pending input. If INHIBIT_HAIRY_ID_P is non-zero, don't try
+ scrolling.
+
+ Value is non-zero if redisplay was stopped due to pending input. */
+
+ int
+ update_frame (f, force_p, inhibit_hairy_id_p)
+ struct frame *f;
+ int force_p;
+ int inhibit_hairy_id_p;
+ {
+ /* 1 means display has been paused because of pending input. */
+ int paused_p;
+ struct window *root_window = XWINDOW (f->root_window);
+
+ if (FRAME_WINDOW_P (f))
+ {
+ /* We are working on window matrix basis. All windows whose
+ flag must_be_updated_p is set have to be updated. */
+
+ /* Record that we are not working on frame matrices. */
+ set_frame_matrix_frame (NULL);
+
+ /* Update all windows in the window tree of F, maybe stopping
+ when pending input is detected. */
+ update_begin (f);
+
+ /* Update the menu bar on X frames that don't have toolkit
+ support. */
+ if (WINDOWP (f->menu_bar_window))
+ update_window (XWINDOW (f->menu_bar_window), 1);
+
+ /* Update the tool-bar window, if present. */
+ if (WINDOWP (f->tool_bar_window))
+ {
+ struct window *w = XWINDOW (f->tool_bar_window);
+
+ /* Update tool-bar window. */
+ if (w->must_be_updated_p)
+ {
+ Lisp_Object tem;
+
+ update_window (w, 1);
+ w->must_be_updated_p = 0;
+
+ /* Swap tool-bar strings. We swap because we want to
+ reuse strings. */
+ tem = f->current_tool_bar_string;
+ f->current_tool_bar_string = f->desired_tool_bar_string;
+ f->desired_tool_bar_string = tem;
+ }
+ }
+
+
+ /* Update windows. */
+ paused_p = update_window_tree (root_window, force_p);
+ update_end (f);
+
+ #if 0 /* This flush is a performance bottleneck under X,
+ and it doesn't seem to be necessary anyway. */
+ rif->flush_display (f);
+ #endif
+ }
+ else
+ {
+ /* We are working on frame matrix basis. Set the frame on whose
+ frame matrix we operate. */
+ set_frame_matrix_frame (f);
+
+ /* Build F's desired matrix from window matrices. */
+ build_frame_matrix (f);
+
+ /* Update the display */
+ update_begin (f);
+ paused_p = update_frame_1 (f, force_p, inhibit_hairy_id_p);
+ update_end (f);
+
+ if (termscript)
+ fflush (termscript);
+ fflush (stdout);
+
+ /* Check window matrices for lost pointers. */
+ #if GLYPH_DEBUG
+ check_window_matrix_pointers (root_window);
+ add_frame_display_history (f, paused_p);
+ #endif
+ }
+
+ /* Reset flags indicating that a window should be updated. */
+ set_window_update_flags (root_window, 0);
+
+ display_completed = !paused_p;
+ return paused_p;
+ }
+
+
+
+ /************************************************************************
+ Window-based updates
+ ************************************************************************/
+
+ /* Perform updates in window tree rooted at W. FORCE_P non-zero means
+ don't stop updating when input is pending. */
+
+ 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;
+ }
+
+
+ /* Update window W if its flag must_be_updated_p is non-zero. If
+ FORCE_P is non-zero, don't stop updating if input is pending. */
+
+ 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));
+
+ /* Record that this is not a frame-based redisplay. */
+ set_frame_matrix_frame (NULL);
+
+ /* Update W. */
+ update_begin (f);
+ update_window (w, force_p);
+ update_end (f);
+
+ /* Reset flag in W. */
+ w->must_be_updated_p = 0;
+ }
+ }
+
+
+ /* Redraw lines from the current matrix of window W that are
+ overlapped by other rows. YB is bottom-most y-position in W. */
+
+ static void
+ redraw_overlapped_rows (w, yb)
+ struct window *w;
+ int yb;
+ {
+ int i;
+
+ /* If rows overlapping others have been changed, the rows being
+ overlapped have to be redrawn. This won't draw lines that have
+ already been drawn in update_window_line because overlapped_p in
+ desired rows is 0, so after row assignment overlapped_p in
+ current rows is 0. */
+ 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;
+ }
+ }
+
+
+ /* Redraw lines from the current matrix of window W that overlap
+ others. YB is bottom-most y-position in W. */
+
+ 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);
+
+ /* Record in neighbour rows that ROW overwrites part of their
+ display. */
+ 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
+
+ /* Check that no row in the current matrix of window W is enabled
+ which is below what's displayed in the window. */
+
+ 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 /* GLYPH_DEBUG */
+
+
+ /* Update display of window W. FORCE_P non-zero means that we should
+ not stop when detecting pending input. */
+
+ 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));
+ #endif
+
+ /* Check that W's frame doesn't have glyph matrices. */
+ xassert (FRAME_WINDOW_P (f));
+ xassert (updating_frame != NULL);
+
+ /* Check pending input the first time so that we can quickly return. */
+ if (redisplay_dont_pause)
+ force_p = 1;
+ else
+ detect_input_pending ();
+
+ /* If forced to complete the update, or if no input is pending, do
+ the update. */
+ 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);
+
+ /* If window has a header line, update it before everything else.
+ Adjust y-positions of other rows by the header line height. */
+ 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;
+
+ /* Update the mode line, if necessary. */
+ 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;
+ }
+
+ /* Find first enabled row. Optimizations in redisplay_internal
+ may lead to an update with only one row enabled. There may
+ be also completely empty matrices. */
+ while (row < end && !row->enabled_p)
+ ++row;
+
+ /* Try reusing part of the display by copying. */
+ if (row < end && !desired_matrix->no_scrolling_p)
+ {
+ int rc = scrolling_window (w, header_line_row != NULL);
+ if (rc < 0)
+ {
+ /* All rows were found to be equal. */
+ paused_p = 0;
+ goto set_cursor;
+ }
+ else if (rc > 0)
+ /* We've scrolled the display. */
+ force_p = 1;
+ changed_p = 1;
+ }
+
+ /* Update the header line after scrolling because a new header
+ line would otherwise overwrite lines at the top of the window
+ that can be scrolled. */
+ 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;
+ }
+
+ /* Update the rest of the lines. */
+ 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;
+
+ /* We'll have to play a little bit with when to
+ detect_input_pending. If it's done too often,
+ scrolling large windows with repeated scroll-up
+ commands will too quickly pause redisplay. */
+ if (!force_p && ++n_updated % preempt_count == 0)
+ detect_input_pending ();
+
+ changed_p |= update_window_line (w, vpos,
+ &mouse_face_overwritten_p);
+
+ /* Mark all rows below the last visible one in the current
+ matrix as invalid. This is necessary because of
+ variable line heights. Consider the case of three
+ successive redisplays, where the first displays 5
+ lines, the second 3 lines, and the third 5 lines again.
+ If the second redisplay wouldn't mark rows in the
+ current matrix invalid, the third redisplay might be
+ tempted to optimize redisplay based on lines displayed
+ in the first redisplay. */
+ 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;
+ }
+
+ /* Was display preempted? */
+ paused_p = row < end;
+
+ set_cursor:
+
+ /* Fix the appearance of overlapping/overlapped rows. */
+ if (!paused_p && !w->pseudo_window_p)
+ {
+ if (changed_p && rif->fix_overlapping_area)
+ {
+ redraw_overlapped_rows (w, yb);
+ redraw_overlapping_rows (w, yb);
+ }
+
+ /* Make cursor visible at cursor position of W. */
+ set_window_cursor_after_update (w);
+
+ #if 0 /* Check that current matrix invariants are satisfied. This is
+ for debugging only. See the comment of check_matrix_invariants. */
+ IF_DEBUG (check_matrix_invariants (w));
+ #endif
+ }
+
+ #if GLYPH_DEBUG
+ /* Remember the redisplay method used to display the matrix. */
+ strcpy (w->current_matrix->method, w->desired_matrix->method);
+ #endif
+
+ /* End the update of window W. Don't set the cursor if we
+ paused updating the display because in this case,
+ set_window_cursor_after_update hasn't been called, and
+ output_cursor doesn't contain the cursor location. */
+ rif->update_window_end_hook (w, !paused_p, mouse_face_overwritten_p);
+ }
+ else
+ paused_p = 1;
+
+ #if GLYPH_DEBUG
+ /* check_current_matrix_flags (w); */
+ add_window_display_history (w, w->current_matrix->method, paused_p);
+ #endif
+
+ clear_glyph_matrix (desired_matrix);
+
+ return paused_p;
+ }
+
+
+ /* Update the display of area AREA in window W, row number VPOS.
+ AREA can be either LEFT_MARGIN_AREA or RIGHT_MARGIN_AREA. */
+
+ 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);
+
+ /* Let functions in xterm.c know what area subsequent X positions
+ will be relative to. */
+ updated_area = area;
+
+ /* Set cursor to start of glyphs, write them, and clear to the end
+ of the area. I don't think that something more sophisticated is
+ necessary here, since marginal areas will not be the default. */
+ 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);
+ }
+
+
+ /* Update the display of the text area of row VPOS in window W.
+ Value is non-zero if display has changed. */
+
+ 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;
+
+ /* Let functions in xterm.c know what area subsequent X positions
+ will be relative to. */
+ updated_area = TEXT_AREA;
+
+ /* If rows are at different X or Y, or rows have different height,
+ or the current row is marked invalid, write the entire line. */
+ 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]);
+
+ /* Clear to end of window. */
+ rif->clear_end_of_line (-1);
+ changed_p = 1;
+
+ /* This erases the cursor. We do this here because
+ notice_overwritten_cursor cannot easily check this, which
+ might indicate that the whole functionality of
+ notice_overwritten_cursor would better be implemented here.
+ On the other hand, we need notice_overwritten_cursor as long
+ as mouse highlighting is done asynchronously outside of
+ redisplay. */
+ if (vpos == w->phys_cursor.vpos)
+ w->phys_cursor_on_p = 0;
+ }
+ else
+ {
+ int stop, i, x;
+ struct glyph *current_glyph = current_row->glyphs[TEXT_AREA];
+ struct glyph *desired_glyph = desired_row->glyphs[TEXT_AREA];
+ int overlapping_glyphs_p = current_row->contains_overlapping_glyphs_p;
+ int desired_stop_pos = desired_row->used[TEXT_AREA];
+
+ /* If the desired row extends its face to the text area end,
+ make sure we write at least one glyph, so that the face
+ extension actually takes place. */
+ 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;
+
+ /* Loop over glyphs that current and desired row may have
+ in common. */
+ while (i < stop)
+ {
+ int can_skip_p = 1;
+
+ /* Skip over glyphs that both rows have in common. These
+ don't have to be written. We can't skip if the last
+ current glyph overlaps the glyph to its right. For
+ example, consider a current row of `if ' with the `f' in
+ Courier bold so that it overlaps the ` ' to its right.
+ If the desired row is ` ', we would skip over the space
+ after the `if' and there would remain a pixel from the
+ `f' on the screen. */
+ 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;
+ }
+
+ /* Consider the case that the current row contains "xxx
+ ppp ggg" in italic Courier font, and the desired row
+ is "xxx ggg". The character `p' has lbearing, `g'
+ has not. The loop above will stop in front of the
+ first `p' in the current row. If we would start
+ writing glyphs there, we wouldn't erase the lbearing
+ of the `p'. The rest of the lbearing problem is then
+ taken care of by draw_glyphs. */
+ 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;
+ }
+ }
+ }
+
+ /* Try to avoid writing the entire rest of the desired row
+ by looking for a resync point. This mainly prevents
+ mode line flickering in the case the mode line is in
+ fixed-pitch font, which it usually will be. */
+ 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;
+
+ /* Find the next glyph that's equal again. */
+ 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;
+ }
+ }
+
+ /* Write the rest. */
+ 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;
+ }
+
+ /* Maybe clear to end of line. */
+ if (MATRIX_ROW_EXTENDS_FACE_P (desired_row))
+ {
+ /* If new row extends to the end of the text area, nothing
+ has to be cleared, if and only if we did a write_glyphs
+ above. This is made sure by setting desired_stop_pos
+ appropriately above. */
+ xassert (i < desired_row->used[TEXT_AREA]);
+ }
+ else if (MATRIX_ROW_EXTENDS_FACE_P (current_row))
+ {
+ /* If old row extends to the end of the text area, clear. */
+ 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)
+ {
+ /* Otherwise clear to the end of the old row. Everything
+ after that position should be clear already. */
+ 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 cursor is displayed at the end of the line, make sure
+ it's cleared. Nowadays we don't have a phys_cursor_glyph
+ with which to erase the cursor (because this method
+ doesn't work with lbearing/rbearing), so we must do it
+ this way. */
+ 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;
+ }
+
+
+ /* Update row VPOS in window W. Value is non-zero if display has been
+ changed. */
+
+ 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;
+
+ /* Set the row being updated. This is important to let xterm.c
+ know what line height values are in effect. */
+ updated_row = desired_row;
+
+ /* A row can be completely invisible in case a desired matrix was
+ built with a vscroll and then make_cursor_line_fully_visible shifts
+ the matrix. Make sure to make such rows current anyway, since
+ we need the correct y-position, for example, in the current matrix. */
+ if (desired_row->mode_line_p
+ || desired_row->visible_height > 0)
+ {
+ xassert (desired_row->enabled_p);
+
+ /* Update display of the left margin area, if there is one. */
+ if (!desired_row->full_width_p
+ && !NILP (w->left_margin_cols))
+ {
+ changed_p = 1;
+ update_marginal_area (w, LEFT_MARGIN_AREA, vpos);
+ }
+
+ /* Update the display of the text area. */
+ if (update_text_area (w, vpos))
+ {
+ changed_p = 1;
+ if (current_row->mouse_face_p)
+ *mouse_face_overwritten_p = 1;
+ }
+
+ /* Update display of the right margin area, if there is one. */
+ if (!desired_row->full_width_p
+ && !NILP (w->right_margin_cols))
+ {
+ changed_p = 1;
+ update_marginal_area (w, RIGHT_MARGIN_AREA, vpos);
+ }
+
+ /* Draw truncation marks etc. */
+ 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);
+ }
+
+ /* Update current_row from desired_row. */
+ make_current (w->desired_matrix, w->current_matrix, vpos);
+ updated_row = NULL;
+ return changed_p;
+ }
+
+
+ /* Set the cursor after an update of window W. This function may only
+ be called from update_window. */
+
+ static void
+ set_window_cursor_after_update (w)
+ struct window *w;
+ {
+ struct frame *f = XFRAME (w->frame);
+ int cx, cy, vpos, hpos;
+
+ /* Not intended for frame matrix updates. */
+ xassert (FRAME_WINDOW_P (f));
+
+ if (cursor_in_echo_area
+ && !NILP (echo_area_buffer[0])
+ /* If we are showing a message instead of the mini-buffer,
+ show the cursor for the message instead. */
+ && XWINDOW (minibuf_window) == w
+ && EQ (minibuf_window, echo_area_window)
+ /* These cases apply only to the frame that contains
+ the active mini-buffer 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)
+ {
+ /* If the mini-buffer is several lines high, find the last
+ line that has any text on it. Note: either all lines
+ are enabled or none. Otherwise we wouldn't be able to
+ determine Y. */
+ 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;
+ }
+
+ /* Window cursor can be out of sync for horizontally split windows. */
+ 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);
+ }
+
+
+ /* Set WINDOW->must_be_updated_p to ON_P for all windows in the window
+ tree rooted at W. */
+
+ 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);
+ }
+ }
+
+
+
+ /***********************************************************************
+ Window-Based Scrolling
+ ***********************************************************************/
+
+ /* Structure describing rows in scrolling_window. */
+
+ struct row_entry
+ {
+ /* Number of occurrences of this row in desired and current matrix. */
+ int old_uses, new_uses;
+
+ /* Vpos of row in new matrix. */
+ int new_line_number;
+
+ /* Bucket index of this row_entry in the hash table row_table. */
+ int bucket;
+
+ /* The row described by this entry. */
+ struct glyph_row *row;
+
+ /* Hash collision chain. */
+ struct row_entry *next;
+ };
+
+ /* A pool to allocate row_entry structures from, and the size of the
+ pool. The pool is reallocated in scrolling_window when we find
+ that we need a larger one. */
+
+ static struct row_entry *row_entry_pool;
+ static int row_entry_pool_size;
+
+ /* Index of next free entry in row_entry_pool. */
+
+ static int row_entry_idx;
+
+ /* The hash table used during scrolling, and the table's size. This
+ table is used to quickly identify equal rows in the desired and
+ current matrix. */
+
+ static struct row_entry **row_table;
+ static int row_table_size;
+
+ /* Vectors of pointers to row_entry structures belonging to the
+ current and desired matrix, and the size of the vectors. */
+
+ static struct row_entry **old_lines, **new_lines;
+ static int old_lines_size, new_lines_size;
+
+ /* A pool to allocate run structures from, and its size. */
+
+ static struct run *run_pool;
+ static int runs_size;
+
+ /* A vector of runs of lines found during scrolling. */
+
+ static struct run **runs;
+
+ /* Add glyph row ROW to the scrolling hash table during the scrolling
+ of window W. */
+
+ 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;
+ }
+
+
+ /* Try to reuse part of the current display of W by scrolling lines.
+ HEADER_LINE_P non-zero means W has a header line.
+
+ The algorithm is taken from Communications of the ACM, Apr78 "A
+ Technique for Isolating Differences Between Files." It should take
+ O(N) time.
+
+ A short outline of the steps of the algorithm
+
+ 1. Skip lines equal at the start and end of both matrices.
+
+ 2. Enter rows in the current and desired matrix into a symbol
+ table, counting how often they appear in both matrices.
+
+ 3. Rows that appear exactly once in both matrices serve as anchors,
+ i.e. we assume that such lines are likely to have been moved.
+
+ 4. Starting from anchor lines, extend regions to be scrolled both
+ forward and backward.
+
+ Value is
+
+ -1 if all rows were found to be equal.
+ 0 to indicate that we did not scroll the display, or
+ 1 if we did scroll. */
+
+ 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;
+
+ /* Skip over rows equal at the start. */
+ 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;
+ }
+
+ /* Give up if some rows in the desired matrix are not enabled. */
+ if (!MATRIX_ROW (desired_matrix, i)->enabled_p)
+ return -1;
+
+ first_old = first_new = i;
+
+ /* Set last_new to the index + 1 of the last enabled row in the
+ desired matrix. */
+ 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;
+
+ /* Set last_old to the index + 1 of the last enabled row in the
+ current matrix. We don't look at the enabled flag here because
+ we plan to reuse part of the display even if other parts are
+ disabled. */
+ 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;
+
+ /* Skip over rows equal at the bottom. */
+ 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;
+
+ /* Nothing to do if all rows are equal. */
+ if (last_new == first_new)
+ return 0;
+
+ /* Reallocate vectors, tables etc. if necessary. */
+
+ 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;
+
+ /* Add rows from the current and desired matrix to the hash table
+ row_hash_table to be able to find equal ones quickly. */
+
+ 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;
+ }
+
+ /* Identify moves based on lines that are unique and equal
+ in both matrices. */
+ 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++;
+
+ /* Record move. */
+ 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;
+
+ /* Extend backward. */
+ 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;
+ }
+
+ /* Extend forward. */
+ 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;
+ }
+
+ /* Insert run into list of all runs. Order runs by copied
+ pixel lines. Note that we record runs that don't have to
+ be copied because they are already in place. This is done
+ because we can avoid calling update_window_line in this
+ case. */
+ 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;
+
+ /* Do the moves. Do it in a way that we don't overwrite something
+ we want to copy later on. This is not solvable in general
+ because there is only one display and we don't have a way to
+ exchange areas on this display. Example:
+
+ +-----------+ +-----------+
+ | A | | B |
+ +-----------+ --> +-----------+
+ | B | | A |
+ +-----------+ +-----------+
+
+ Instead, prefer bigger moves, and invalidate moves that would
+ copy from where we copied to. */
+
+ for (i = 0; i < nruns; ++i)
+ if (runs[i]->nrows > 0)
+ {
+ struct run *r = runs[i];
+
+ /* Copy on the display. */
+ if (r->current_y != r->desired_y)
+ {
+ rif->scroll_run_hook (w, r);
+
+ /* Invalidate runs that copy from where we copied to. */
+ 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;
+ }
+ }
+
+ /* Assign matrix rows. */
+ 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;
+ }
+ }
+
+ /* Clear the hash table, for the next time. */
+ for (i = 0; i < row_entry_idx; ++i)
+ row_table[row_entry_pool[i].bucket] = NULL;
+
+ /* Value is non-zero to indicate that we scrolled the display. */
+ return 1;
+ }
+
+
+
+ /************************************************************************
+ Frame-Based Updates
+ ************************************************************************/
+
+ /* Update the desired frame matrix of frame F.
+
+ FORCE_P non-zero means that the update should not be stopped by
+ pending input. INHIBIT_HAIRY_ID_P non-zero means that scrolling
+ should not be tried.
+
+ Value is non-zero if update was stopped due to pending input. */
+
+ static int
+ update_frame_1 (f, force_p, inhibit_id_p)
+ struct frame *f;
+ int force_p;
+ int inhibit_id_p;
+ {
+ /* Frame matrices to work on. */
+ 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 we cannot insert/delete lines, it's no use trying it. */
+ if (!line_ins_del_ok)
+ inhibit_id_p = 1;
+
+ /* See if any of the desired lines are enabled; don't compute for
+ i/d line if just want cursor motion. */
+ for (i = 0; i < desired_matrix->nrows; i++)
+ if (MATRIX_ROW_ENABLED_P (desired_matrix, i))
+ break;
+
+ /* Try doing i/d line, if not yet inhibited. */
+ if (!inhibit_id_p && i < desired_matrix->nrows)
+ force_p |= scrolling (f);
+
+ /* Update the individual lines as needed. Do bottom line first. */
+ if (MATRIX_ROW_ENABLED_P (desired_matrix, desired_matrix->nrows - 1))
+ update_frame_line (f, desired_matrix->nrows - 1);
+
+ /* Now update the rest of the lines. */
+ 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))
+ {
+ /* Flush out every so many lines.
+ Also flush out if likely to have more than 1k buffered
+ otherwise. I'm told that some telnet connections get
+ really screwed by more than 1k output at once. */
+ 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)
+ /* Probably not a tty. Ignore the error and reset
+ the outq count. */
+ 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_LINES (f) - 1) ? i : 0;
+
+ /* Now just clean up termcap drivers and set cursor, etc. */
+ if (!pause)
+ {
+ if ((cursor_in_echo_area
+ /* If we are showing a message instead of the mini-buffer,
+ show the cursor for the message instead of for the
+ (now hidden) mini-buffer contents. */
+ || (EQ (minibuf_window, selected_window)
+ && EQ (minibuf_window, echo_area_window)
+ && !NILP (echo_area_buffer[0])))
+ /* These cases apply only to the frame that contains
+ the active mini-buffer window. */
+ && FRAME_HAS_MINIBUF_P (f)
+ && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
+ {
+ int top = WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f)));
+ int row, col;
+
+ if (cursor_in_echo_area < 0)
+ {
+ /* Negative value of cursor_in_echo_area means put
+ cursor at beginning of line. */
+ row = top;
+ col = 0;
+ }
+ else
+ {
+ /* Positive value of cursor_in_echo_area means put
+ cursor at the end of the prompt. If the mini-buffer
+ is several lines high, find the last line that has
+ any text on it. */
+ row = FRAME_LINES (f);
+ do
+ {
+ --row;
+ col = 0;
+
+ if (MATRIX_ROW_ENABLED_P (current_matrix, row))
+ {
+ /* Frame rows are filled up with spaces that
+ must be ignored here. */
+ 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);
+
+ /* Make sure COL is not out of range. */
+ if (col >= FRAME_CURSOR_X_LIMIT (f))
+ {
+ /* If we have another row, advance cursor into it. */
+ if (row < FRAME_LINES (f) - 1)
+ {
+ col = FRAME_LEFT_SCROLL_BAR_COLS (f);
+ row++;
+ }
+ /* Otherwise move it back in range. */
+ else
+ col = FRAME_CURSOR_X_LIMIT (f) - 1;
+ }
+ }
+
+ cursor_to (row, col);
+ }
+ else
+ {
+ /* We have only one cursor on terminal frames. Use it to
+ display the cursor of the selected window. */
+ struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
+ if (w->cursor.vpos >= 0
+ /* The cursor vpos may be temporarily out of bounds
+ in the following situation: There is one window,
+ with the cursor in the lower half of it. The window
+ is split, and a message causes a redisplay before
+ a new cursor position has been computed. */
+ && w->cursor.vpos < WINDOW_TOTAL_LINES (w))
+ {
+ int x = WINDOW_TO_FRAME_HPOS (w, w->cursor.hpos);
+ int y = WINDOW_TO_FRAME_VPOS (w, w->cursor.vpos);
+
+ if (INTEGERP (w->left_margin_cols))
+ x += XFASTINT (w->left_margin_cols);
+
+ /* x = max (min (x, FRAME_TOTAL_COLS (f) - 1), 0); */
+ cursor_to (y, x);
+ }
+ }
+ }
+
+ do_pause:
+
+ clear_desired_matrices (f);
+ return pause;
+ }
+
+
+ /* Do line insertions/deletions on frame F for frame-based redisplay. */
+
+ int
+ scrolling (frame)
+ struct frame *frame;
+ {
+ int unchanged_at_top, unchanged_at_bottom;
+ int window_size;
+ int changed_lines;
+ int *old_hash = (int *) alloca (FRAME_LINES (frame) * sizeof (int));
+ int *new_hash = (int *) alloca (FRAME_LINES (frame) * sizeof (int));
+ int *draw_cost = (int *) alloca (FRAME_LINES (frame) * sizeof (int));
+ int *old_draw_cost = (int *) alloca (FRAME_LINES (frame) * sizeof (int));
+ register int i;
+ int free_at_end_vpos = FRAME_LINES (frame);
+ struct glyph_matrix *current_matrix = frame->current_matrix;
+ struct glyph_matrix *desired_matrix = frame->desired_matrix;
+
+ if (!current_matrix)
+ abort ();
+
+ /* Compute hash codes of all the lines. Also calculate number of
+ changed lines, number of unchanged lines at the beginning, and
+ number of unchanged lines at the end. */
+ changed_lines = 0;
+ unchanged_at_top = 0;
+ unchanged_at_bottom = FRAME_LINES (frame);
+ for (i = 0; i < FRAME_LINES (frame); i++)
+ {
+ /* Give up on this scrolling if some old lines are not enabled. */
+ 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))
+ {
+ /* This line cannot be redrawn, so don't let scrolling mess it. */
+ new_hash[i] = old_hash[i];
+ #define INFINITY 1000000 /* Taken from scroll.c */
+ draw_cost[i] = INFINITY;
+ }
+ else
+ {
+ new_hash[i] = line_hash_code (MATRIX_ROW (desired_matrix, i));
+ draw_cost[i] = line_draw_cost (desired_matrix, i);
+ }
+
+ if (old_hash[i] != new_hash[i])
+ {
+ changed_lines++;
+ unchanged_at_bottom = FRAME_LINES (frame) - i - 1;
+ }
+ else if (i == unchanged_at_top)
+ unchanged_at_top++;
+ old_draw_cost[i] = line_draw_cost (current_matrix, i);
+ }
+
+ /* If changed lines are few, don't allow preemption, don't scroll. */
+ if ((!scroll_region_ok && changed_lines < baud_rate / 2400)
+ || unchanged_at_bottom == FRAME_LINES (frame))
+ return 1;
+
+ window_size = (FRAME_LINES (frame) - unchanged_at_top
+ - unchanged_at_bottom);
+
+ if (scroll_region_ok)
+ free_at_end_vpos -= unchanged_at_bottom;
+ else if (memory_below_frame)
+ free_at_end_vpos = -1;
+
+ /* If large window, fast terminal and few lines in common between
+ current frame and desired frame, don't bother with i/d calc. */
+ if (!scroll_region_ok && window_size >= 18 && baud_rate > 2400
+ && (window_size >=
+ 10 * scrolling_max_lines_saved (unchanged_at_top,
+ FRAME_LINES (frame) -
unchanged_at_bottom,
+ old_hash, new_hash, draw_cost)))
+ return 0;
+
+ if (window_size < 2)
+ return 0;
+
+ scrolling_1 (frame, window_size, unchanged_at_top, unchanged_at_bottom,
+ draw_cost + unchanged_at_top - 1,
+ old_draw_cost + unchanged_at_top - 1,
+ old_hash + unchanged_at_top - 1,
+ new_hash + unchanged_at_top - 1,
+ free_at_end_vpos - unchanged_at_top);
+
+ return 0;
+ }
+
+
+ /* Count the number of blanks at the start of the vector of glyphs R
+ which is LEN glyphs long. */
+
+ 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;
+ }
+
+
+ /* Count the number of glyphs in common at the start of the glyph
+ vectors STR1 and STR2. END1 is the end of STR1 and END2 is the end
+ of STR2. Value is the number of equal glyphs equal at the start. */
+
+ 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;
+ }
+
+
+ /* Char insertion/deletion cost vector, from term.c */
+
+ extern int *char_ins_del_vector;
+ #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_TOTAL_COLS((f))])
+
+
+ /* Perform a frame-based update on line VPOS in frame FRAME. */
+
+ 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;
+
+ /* Current row not enabled means it has unknown contents. We must
+ write the whole desired line in that case. */
+ 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];
+
+ /* Ignore trailing spaces, if we can. */
+ if (!write_spaces_p)
+ while (olen > 0 && CHAR_GLYPH_SPACE_P (obody[olen-1]))
+ olen--;
+ }
+
+ current_row->enabled_p = 1;
+ current_row->used[TEXT_AREA] = desired_row->used[TEXT_AREA];
+
+ /* If desired line is empty, just clear the line. */
+ 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 display line has unknown contents, write the whole line. */
+ if (must_write_whole_line_p)
+ {
+ /* Ignore spaces at the end, if we can. */
+ if (!write_spaces_p)
+ while (nlen > 0 && CHAR_GLYPH_SPACE_P (nbody[nlen - 1]))
+ --nlen;
+
+ /* Write the contents of the desired line. */
+ if (nlen)
+ {
+ cursor_to (vpos, 0);
+ write_glyphs (nbody, nlen);
+ }
+
+ /* Don't call clear_end_of_line if we already wrote the whole
+ line. The cursor will not be at the right margin in that
+ case but in the line below. */
+ if (nlen < FRAME_TOTAL_COLS (f))
+ {
+ cursor_to (vpos, nlen);
+ clear_end_of_line (FRAME_TOTAL_COLS (f));
+ }
+ else
+ /* Make sure we are in the right row, otherwise cursor movement
+ with cmgoto might use `ch' in the wrong row. */
+ cursor_to (vpos, 0);
+
+ make_current (desired_matrix, current_matrix, vpos);
+ return;
+ }
+
+ /* Pretend trailing spaces are not there at all,
+ unless for one reason or another we must write all spaces. */
+ if (!write_spaces_p)
+ while (nlen > 0 && CHAR_GLYPH_SPACE_P (nbody[nlen - 1]))
+ nlen--;
+
+ /* If there's no i/d char, quickly do the best we can without it. */
+ if (!char_ins_del_ok)
+ {
+ int i, j;
+
+ /* Find the first glyph in desired row that doesn't agree with
+ a glyph in the current row, and write the rest from there on. */
+ for (i = 0; i < nlen; i++)
+ {
+ if (i >= olen || !GLYPH_EQUAL_P (nbody + i, obody + i))
+ {
+ /* Find the end of the run of different glyphs. */
+ j = i + 1;
+ while (j < nlen
+ && (j >= olen
+ || !GLYPH_EQUAL_P (nbody + j, obody + j)
+ || CHAR_GLYPH_PADDING_P (nbody[j])))
+ ++j;
+
+ /* Output this run of non-matching chars. */
+ cursor_to (vpos, i);
+ write_glyphs (nbody + i, j - i);
+ i = j - 1;
+
+ /* Now find the next non-match. */
+ }
+ }
+
+ /* Clear the rest of the line, or the non-clear part of it. */
+ if (olen > nlen)
+ {
+ cursor_to (vpos, nlen);
+ clear_end_of_line (olen);
+ }
+
+ /* Make current row = desired row. */
+ make_current (desired_matrix, current_matrix, vpos);
+ return;
+ }
+
+ /* Here when CHAR_INS_DEL_OK != 0, i.e. we can insert or delete
+ characters in a row. */
+
+ if (!olen)
+ {
+ /* If current line is blank, skip over initial spaces, if
+ possible, and write the rest. */
+ if (write_spaces_p)
+ nsp = 0;
+ else
+ nsp = count_blanks (nbody, nlen);
+
+ if (nlen > nsp)
+ {
+ cursor_to (vpos, nsp);
+ write_glyphs (nbody + nsp, nlen - nsp);
+ }
+
+ /* Exchange contents between current_frame and new_frame. */
+ make_current (desired_matrix, current_matrix, vpos);
+ return;
+ }
+
+ /* Compute number of leading blanks in old and new contents. */
+ osp = count_blanks (obody, olen);
+ nsp = (colored_spaces_p ? 0 : count_blanks (nbody, nlen));
+
+ /* Compute number of matching chars starting with first non-blank. */
+ begmatch = count_match (obody + osp, obody + olen,
+ nbody + nsp, nbody + nlen);
+
+ /* Spaces in new match implicit space past the end of old. */
+ /* A bug causing this to be a no-op was fixed in 18.29. */
+ if (!write_spaces_p && osp + begmatch == olen)
+ {
+ np1 = nbody + nsp;
+ while (np1 + begmatch < nend && CHAR_GLYPH_SPACE_P (np1[begmatch]))
+ ++begmatch;
+ }
+
+ /* Avoid doing insert/delete char
+ just cause number of leading spaces differs
+ when the following text does not match. */
+ if (begmatch == 0 && osp != nsp)
+ osp = nsp = min (osp, nsp);
+
+ /* Find matching characters at end of line */
+ 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 gets the distance to insert or delete.
+ endmatch is how many characters we save by doing so.
+ Is it worth it? */
+
+ tem = (nlen - nsp) - (olen - osp);
+ if (endmatch && tem
+ && (!char_ins_del_ok || endmatch <= char_ins_del_cost (f)[tem]))
+ endmatch = 0;
+
+ /* nsp - osp is the distance to insert or delete.
+ If that is nonzero, begmatch is known to be nonzero also.
+ begmatch + endmatch is how much we save by doing the ins/del.
+ Is it worth it? */
+
+ 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);
+ }
+
+ /* Now go through the line, inserting, writing and
+ deleting as appropriate. */
+
+ if (osp > nsp)
+ {
+ cursor_to (vpos, nsp);
+ delete_glyphs (osp - nsp);
+ }
+ else if (nsp > osp)
+ {
+ /* If going to delete chars later in line
+ and insert earlier in the line,
+ must delete first to avoid losing data in the insert */
+ 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 new text being written reaches right margin, there is
+ no need to do clear-to-eol at the end of this function
+ (and it would not be safe, since cursor is not going to
+ be "at the margin" after the text is done). */
+ if (nlen == FRAME_TOTAL_COLS (f))
+ olen = 0;
+
+ /* Function write_glyphs is prepared to do nothing
+ if passed a length <= 0. Check it here to avoid
+ unnecessary cursor movement. */
+ if (nlen - tem > 0)
+ {
+ cursor_to (vpos, nsp + begmatch);
+ write_glyphs (nbody + nsp + begmatch, nlen - tem);
+ }
+ }
+ else if (nlen > olen)
+ {
+ /* Here, we used to have the following simple code:
+ ----------------------------------------
+ write_glyphs (nbody + nsp + begmatch, olen - tem);
+ insert_glyphs (nbody + nsp + begmatch + olen - tem, nlen - olen);
+ ----------------------------------------
+ but it doesn't work if nbody[nsp + begmatch + olen - tem]
+ is a padding glyph. */
+ int out = olen - tem; /* Columns to be overwritten originally. */
+ int del;
+
+ cursor_to (vpos, nsp + begmatch);
+
+ /* Calculate columns we can actually overwrite. */
+ while (CHAR_GLYPH_PADDING_P (nbody[nsp + begmatch + out]))
+ out--;
+ write_glyphs (nbody + nsp + begmatch, out);
+
+ /* If we left columns to be overwritten, we must delete them. */
+ del = olen - tem - out;
+ if (del > 0)
+ delete_glyphs (del);
+
+ /* At last, we insert columns not yet written out. */
+ 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 any unerased characters remain after the new line, erase them. */
+ if (olen > nlen)
+ {
+ cursor_to (vpos, nlen);
+ clear_end_of_line (olen);
+ }
+
+ /* Exchange contents between current_frame and new_frame. */
+ make_current (desired_matrix, current_matrix, vpos);
+ }
+
+
+
+ /***********************************************************************
+ X/Y Position -> Buffer Position
+ ***********************************************************************/
+
+ /* Determine what's under window-relative pixel position (*X, *Y).
+ Return in *OBJECT the object (string or buffer) that's there.
+ Return in *POS the position in that object. Adjust *X and *Y
+ to character boundaries. */
+
+ 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_LEFT_MARGIN_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;
+ }
+
+
+ /* Value is the string under window-relative coordinates X/Y in the
+ mode or header line of window W, or nil if none. MODE_LINE_P non-zero
+ means look at the mode line. *CHARPOS is set to the position in
+ the string returned. */
+
+ Lisp_Object
+ mode_line_string (w, x, y, part, charpos)
+ struct window *w;
+ int x, y;
+ enum window_part part;
+ int *charpos;
+ {
+ struct glyph_row *row;
+ struct glyph *glyph, *end;
+ int x0;
+ Lisp_Object string = Qnil;
+
+ if (part == ON_MODE_LINE)
+ row = MATRIX_MODE_LINE_ROW (w->current_matrix);
+ else
+ row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
+
+ if (row->mode_line_p && row->enabled_p)
+ {
+ /* Find the glyph under X. If we find one with a string object,
+ it's the one we were looking for. */
+ 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;
+ }
+
+
+ /* Value is the string under window-relative coordinates X/Y in either
+ marginal area, or nil if none. *CHARPOS is set to the position in
+ the string returned. */
+
+ Lisp_Object
+ marginal_area_string (w, x, y, part, charpos)
+ struct window *w;
+ int x, y;
+ enum window_part part;
+ int *charpos;
+ {
+ struct glyph_row *row = w->current_matrix->rows;
+ struct glyph *glyph, *end;
+ int x0, i, wy = y;
+ int area;
+ Lisp_Object string = Qnil;
+
+ if (part == ON_LEFT_MARGIN)
+ area = LEFT_MARGIN_AREA;
+ else if (part == ON_RIGHT_MARGIN)
+ area = RIGHT_MARGIN_AREA;
+ else
+ abort ();
+
+ for (i = 0; row->enabled_p && i < w->current_matrix->nrows; ++i, ++row)
+ if (wy >= row->y && wy < MATRIX_ROW_BOTTOM_Y (row))
+ break;
+
+ if (row->enabled_p)
+ {
+ /* Find the glyph under X. If we find one with a string object,
+ it's the one we were looking for. */
+ glyph = row->glyphs[area];
+ end = glyph + row->used[area];
+
+ if (area == RIGHT_MARGIN_AREA)
+ x0 = ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+ ? WINDOW_LEFT_FRINGE_WIDTH (w)
+ : WINDOW_TOTAL_FRINGE_WIDTH (w))
+ + window_box_width (w, LEFT_MARGIN_AREA)
+ + window_box_width (w, TEXT_AREA));
+ else
+ x0 = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+ ? WINDOW_LEFT_FRINGE_WIDTH (w)
+ : 0);
+
+ for (; glyph < end; x0 += glyph->pixel_width, ++glyph)
+ if (x >= x0 && x < x0 + glyph->pixel_width)
+ {
+ string = glyph->object;
+ *charpos = glyph->charpos;
+ break;
+ }
+ }
+
+ return string;
+ }
+
+
+ /***********************************************************************
+ Changing Frame Sizes
+ ***********************************************************************/
+
+ #ifdef SIGWINCH
+
+ SIGTYPE
+ window_change_signal (signalnum) /* If we don't have an argument, */
+ int signalnum; /* some compilers complain in signal calls. */
+ {
+ int width, height;
+ #ifndef USE_CRT_DLL
+ extern int errno;
+ #endif
+ int old_errno = errno;
+
+ get_frame_size (&width, &height);
+
+ /* The frame size change obviously applies to a termcap-controlled
+ frame. Find such a frame in the list, and assume it's the only
+ one (since the redisplay code always writes to stdout, not a
+ FILE * specified in the frame structure). Record the new size,
+ but don't reallocate the data structures now. Let that be done
+ later outside of the signal handler. */
+
+ {
+ 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 /* SIGWINCH */
+
+
+ /* Do any change in frame size that was requested by a signal. SAFE
+ non-zero means this function is called from a place where it is
+ safe to change frame sizes while a redisplay is in progress. */
+
+ void
+ do_pending_window_change (safe)
+ int safe;
+ {
+ /* If window_change_signal should have run before, run it now. */
+ if (redisplaying_p && !safe)
+ return;
+
+ while (delayed_size_change)
+ {
+ Lisp_Object tail, frame;
+
+ delayed_size_change = 0;
+
+ FOR_EACH_FRAME (tail, frame)
+ {
+ struct frame *f = XFRAME (frame);
+
+ if (f->new_text_lines != 0 || f->new_text_cols != 0)
+ change_frame_size (f, f->new_text_lines, f->new_text_cols,
+ 0, 0, safe);
+ }
+ }
+ }
+
+
+ /* Change the frame height and/or width. Values may be given as zero to
+ indicate no change is to take place.
+
+ If DELAY is non-zero, then assume we're being called from a signal
+ handler, and queue the change for later - perhaps the next
+ redisplay. Since this tries to resize windows, we can't call it
+ from a signal handler.
+
+ SAFE non-zero means this function is called from a place where it's
+ safe to change frame sizes while a redisplay is in progress. */
+
+ 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))
+ {
+ /* When using termcap, or on MS-DOS, all frames use
+ the same screen, so a change in size affects all frames. */
+ FOR_EACH_FRAME (tail, frame)
+ if (! FRAME_WINDOW_P (XFRAME (frame)))
+ change_frame_size_1 (XFRAME (frame), newheight, newwidth,
+ pretend, delay, safe);
+ }
+ else
+ change_frame_size_1 (f, newheight, newwidth, pretend, delay, safe);
+ }
+
+ static void
+ change_frame_size_1 (f, newheight, newwidth, pretend, delay, safe)
+ register struct frame *f;
+ int newheight, newwidth, pretend, delay, safe;
+ {
+ int new_frame_total_cols;
+ int count = SPECPDL_INDEX ();
+
+ /* If we can't deal with the change now, queue it for later. */
+ if (delay || (redisplaying_p && !safe))
+ {
+ f->new_text_lines = newheight;
+ f->new_text_cols = newwidth;
+ delayed_size_change = 1;
+ return;
+ }
+
+ /* This size-change overrides any pending one for this frame. */
+ f->new_text_lines = 0;
+ f->new_text_cols = 0;
+
+ /* If an argument is zero, set it to the current value. */
+ if (newheight == 0)
+ newheight = FRAME_LINES (f);
+ if (newwidth == 0)
+ newwidth = FRAME_COLS (f);
+
+ /* Compute width of windows in F.
+ This is the width of the frame without vertical scroll bars. */
+ new_frame_total_cols = FRAME_TOTAL_COLS_ARG (f, newwidth);
+
+ /* Round up to the smallest acceptable size. */
+ check_frame_size (f, &newheight, &newwidth);
+
+ /* If we're not changing the frame size, quit now. */
+ if (newheight == FRAME_LINES (f)
+ && new_frame_total_cols == FRAME_TOTAL_COLS (f))
+ return;
+
+ BLOCK_INPUT;
+
+ #ifdef MSDOS
+ /* We only can set screen dimensions to certain values supported
+ by our video hardware. Try to find the smallest size greater
+ or equal to the requested dimensions. */
+ dos_set_window_size (&newheight, &newwidth);
+ #endif
+
+ if (newheight != FRAME_LINES (f))
+ {
+ if (FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
+ {
+ /* Frame has both root and mini-buffer. */
+ XSETFASTINT (XWINDOW (FRAME_ROOT_WINDOW (f))->top_line,
+ FRAME_TOP_MARGIN (f));
+ set_window_height (FRAME_ROOT_WINDOW (f),
+ (newheight
+ - 1
+ - FRAME_TOP_MARGIN (f)),
+ 0);
+ XSETFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top_line,
+ newheight - 1);
+ set_window_height (FRAME_MINIBUF_WINDOW (f), 1, 0);
+ }
+ else
+ /* Frame has just one top-level window. */
+ set_window_height (FRAME_ROOT_WINDOW (f),
+ newheight - FRAME_TOP_MARGIN (f), 0);
+
+ if (FRAME_TERMCAP_P (f) && !pretend)
+ FrameRows = newheight;
+ }
+
+ if (new_frame_total_cols != FRAME_TOTAL_COLS (f))
+ {
+ set_window_width (FRAME_ROOT_WINDOW (f), new_frame_total_cols, 0);
+ if (FRAME_HAS_MINIBUF_P (f))
+ set_window_width (FRAME_MINIBUF_WINDOW (f), new_frame_total_cols, 0);
+
+ if (FRAME_TERMCAP_P (f) && !pretend)
+ FrameCols = newwidth;
+
+ if (WINDOWP (f->tool_bar_window))
+ XSETFASTINT (XWINDOW (f->tool_bar_window)->total_cols, newwidth);
+ }
+
+ FRAME_LINES (f) = newheight;
+ SET_FRAME_COLS (f, newwidth);
+
+ {
+ struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
+ int text_area_x, text_area_y, text_area_width, text_area_height;
+
+ window_box (w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width,
+ &text_area_height);
+ if (w->cursor.x >= text_area_x + text_area_width)
+ w->cursor.hpos = w->cursor.x = 0;
+ if (w->cursor.y >= text_area_y + text_area_height)
+ w->cursor.vpos = w->cursor.y = 0;
+ }
+
+ adjust_glyphs (f);
+ calculate_costs (f);
+ SET_FRAME_GARBAGED (f);
+ f->resized_p = 1;
+
+ UNBLOCK_INPUT;
+
+ record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+
+ /* This isn't quite a no-op: it runs window-configuration-change-hook. */
+ Fset_window_buffer (FRAME_SELECTED_WINDOW (f),
+ XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer, Qt);
+
+ unbind_to (count, Qnil);
+ }
+
+
+
+ /***********************************************************************
+ Terminal Related Lisp Functions
+ ***********************************************************************/
+
+ DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript,
+ 1, 1, "FOpen termscript file: ",
+ doc: /* Start writing all terminal output to FILE as well as the
terminal.
+ 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 (SDATA (file), "w");
+ if (termscript == 0)
+ report_file_error ("Opening termscript", Fcons (file, Qnil));
+ }
+ return Qnil;
+ }
+
+
+ DEFUN ("send-string-to-terminal", Fsend_string_to_terminal,
+ Ssend_string_to_terminal, 1, 1, 0,
+ doc: /* Send STRING to the terminal without alteration.
+ Control characters in STRING will have terminal-dependent effects. */)
+ (string)
+ Lisp_Object string;
+ {
+ /* ??? Perhaps we should do something special for multibyte strings here.
*/
+ CHECK_STRING (string);
+ fwrite (SDATA (string), 1, SBYTES (string), stdout);
+ fflush (stdout);
+ if (termscript)
+ {
+ fwrite (SDATA (string), 1, SBYTES (string),
+ termscript);
+ fflush (termscript);
+ }
+ return Qnil;
+ }
+
+
+ DEFUN ("ding", Fding, Sding, 0, 1, 0,
+ doc: /* Beep, or flash the screen.
+ Also, unless an argument is given,
+ 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) /* Stop executing a keyboard macro. */
+ error ("Keyboard macro terminated by a command ringing the bell");
+ else
+ ring_bell ();
+ fflush (stdout);
+ }
+
+
+
+ /***********************************************************************
+ Sleeping, Waiting
+ ***********************************************************************/
+
+ DEFUN ("sleep-for", Fsleep_for, Ssleep_for, 1, 2, 0,
+ doc: /* Pause, without updating display, for SECONDS seconds.
+ SECONDS may be a floating-point value, meaning that you can wait for a
+ fraction of a second. Optional second arg MILLISECONDS specifies an
+ additional wait period, in milliseconds; this may be useful if your
+ Emacs was built without floating point support.
+ \(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);
+ 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
+
+ /* Assure that 0 <= usec < 1000000. */
+ if (usec < 0)
+ {
+ /* We can't rely on the rounding being correct if usec is negative. */
+ 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);
+ }
+
+ /* We should always have wait_reading_process_input; we have a dummy
+ implementation for systems which don't support subprocesses. */
+ #if 0
+ /* No wait_reading_process_input */
+ immediate_quit = 1;
+ QUIT;
+
+ #ifdef VMS
+ sys_sleep (sec);
+ #else /* not VMS */
+ /* The reason this is done this way
+ (rather than defined (H_S) && defined (H_T))
+ is because the VMS preprocessor doesn't grok `defined'. */
+ #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 /* not HAVE_SELECT */
+ sleep (sec);
+ #endif /* HAVE_SELECT */
+ #endif /* not VMS */
+
+ immediate_quit = 0;
+ #endif /* no subprocesses */
+
+ return Qnil;
+ }
+
+
+ /* This is just like wait_reading_process_input, except that
+ it does the redisplay.
+
+ It's also much like Fsit_for, except that it can be used for
+ waiting for input as well. */
+
+ 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) || !NILP (Vexecuting_macro))
+ 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,
+ doc: /* Perform redisplay, then wait for SECONDS seconds or until
input is available.
+ SECONDS may be a floating-point value, meaning that you can wait for a
+ fraction of a second.
+ \(Not all operating systems support waiting for a fraction of a second.)
+ Optional arg NODISP non-nil means don't redisplay, just wait for input.
+ Redisplay is preempted as always if input arrives, and does not happen
+ if input is available before it starts.
+ Value is t if waited the full time with no input arriving.
+
+ An obsolete but still supported form is
+ \(sit-for SECONDS &optional MILLISECONDS NODISP)
+ Where the optional arg MILLISECONDS specifies an additional wait period,
+ in milliseconds; this was useful when Emacs was built without
+ floating point support.
+ usage: (sit-for SECONDS &optional NODISP OLD-NODISP) */)
+
+ /* The `old-nodisp' stuff is there so that the arglist has the correct
+ length. Otherwise, `defdvice' will redefine it with fewer args. */
+ (seconds, milliseconds, nodisp)
+ Lisp_Object seconds, milliseconds, nodisp;
+ {
+ int sec, usec;
+
+ if (NILP (nodisp) && !NUMBERP (milliseconds))
+ { /* New style. */
+ nodisp = milliseconds;
+ milliseconds = Qnil;
+ }
+
+ if (NILP (milliseconds))
+ XSETINT (milliseconds, 0);
+ else
+ CHECK_NUMBER (milliseconds);
+ usec = XINT (milliseconds) * 1000;
+
+ {
+ double duration = extract_float (seconds);
+ sec = (int) duration;
+ usec += (duration - sec) * 1000000;
+ }
+
+ #ifndef EMACS_HAS_USECS
+ if (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));
+ }
+
+
+
+ /***********************************************************************
+ Other Lisp Functions
+ ***********************************************************************/
+
+ /* A vector of size >= 2 * NFRAMES + 3 * NBUFFERS + 1, containing the
+ session's frames, frame names, buffers, buffer-read-only flags, and
+ buffer-modified-flags, and a trailing sentinel (so we don't need to
+ add length checks). */
+
+ 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,
+ doc: /* Return non-nil if the frame and buffer state appears to have
changed.
+ The state variable is an internal vector containing all frames and buffers,
+ aside from buffers whose names start with space,
+ along with the buffers' read-only and modified flags, which allows a fast
+ check to see whether the menu bars might need to be recomputed.
+ If this function returns non-nil, it updates the internal vector to reflect
+ the current state. */)
+ ()
+ {
+ 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;
+ }
+ /* Check that the buffer info matches.
+ No need to test for the end of the vector
+ because the last element of the vector is lambda
+ and that will always cause a mismatch. */
+ for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail))
+ {
+ buf = XCDR (XCAR (tail));
+ /* Ignore buffers that aren't included in buffer lists. */
+ if (SREF (XBUFFER (buf)->name, 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;
+ }
+ /* Detect deletion of a buffer at the end of the list. */
+ if (EQ (*vecp, Qlambda))
+ return Qnil;
+ changed:
+ /* Start with 1 so there is room for at least one lambda at the end. */
+ n = 1;
+ FOR_EACH_FRAME (tail, frame)
+ n += 2;
+ for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail))
+ n += 3;
+ /* Reallocate the vector if it's grown, or if it's shrunk a lot. */
+ if (n > XVECTOR (frame_and_buffer_state)->size
+ || n + 20 < XVECTOR (frame_and_buffer_state)->size / 2)
+ /* Add 20 extra so we grow it less often. */
+ 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));
+ /* Ignore buffers that aren't included in buffer lists. */
+ if (SREF (XBUFFER (buf)->name, 0) == ' ')
+ continue;
+ *vecp++ = buf;
+ *vecp++ = XBUFFER (buf)->read_only;
+ *vecp++ = Fbuffer_modified_p (buf);
+ }
+ /* Fill up the vector with lambdas (always at least one). */
+ *vecp++ = Qlambda;
+ while (vecp - XVECTOR (frame_and_buffer_state)->contents
+ < XVECTOR (frame_and_buffer_state)->size)
+ *vecp++ = Qlambda;
+ /* Make sure we didn't overflow the vector. */
+ if (vecp - XVECTOR (frame_and_buffer_state)->contents
+ > XVECTOR (frame_and_buffer_state)->size)
+ abort ();
+ return Qt;
+ }
+
+
+
+ /***********************************************************************
+ Initialization
+ ***********************************************************************/
+
+ char *terminal_type;
+
+ /* Initialization done when Emacs fork is started, before doing stty.
+ Determine terminal type and set terminal_driver. Then invoke its
+ decoding routine to set up variables in the terminal package. */
+
+ void
+ init_display ()
+ {
+ #ifdef HAVE_X_WINDOWS
+ extern int display_arg;
+ #endif
+
+ /* Construct the space glyph. */
+ 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;
+
+ /* Now is the time to initialize this; it's used by init_sys_modes
+ during startup. */
+ Vwindow_system = Qnil;
+
+ /* If the user wants to use a window system, we shouldn't bother
+ initializing the terminal. This is especially important when the
+ terminal is so dumb that emacs gives up before and doesn't bother
+ using the window system.
+
+ If the DISPLAY environment variable is set and nonempty,
+ try to use X, and die with an error message if that doesn't work. */
+
+ #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 (GNU_LINUX) && defined (HAVE_LIBNCURSES)
+ /* In some versions of ncurses,
+ tputs crashes if we have not called tgetent.
+ So call tgetent. */
+ { char b[2044]; tgetent (b, "xterm");}
+ #endif
+ adjust_frame_glyphs_initially ();
+ return;
+ }
+ #endif /* HAVE_X_WINDOWS */
+
+ #ifdef HAVE_NTGUI
+ if (!inhibit_window_system)
+ {
+ Vwindow_system = intern ("w32");
+ Vwindow_system_version = make_number (1);
+ adjust_frame_glyphs_initially ();
+ return;
+ }
+ #endif /* HAVE_NTGUI */
+
+ #ifdef MAC_OS
+ if (!inhibit_window_system)
+ {
+ Vwindow_system = intern ("mac");
+ Vwindow_system_version = make_number (1);
+ adjust_frame_glyphs_initially ();
+ return;
+ }
+ #endif /* MAC_OS */
+
+ /* If no window system has been specified, try to use the terminal. */
+ if (! isatty (0))
+ {
+ fatal ("standard input is not a tty");
+ exit (1);
+ }
+
+ /* Look at the TERM variable. */
+ 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
+ /* VMS DCL tends to up-case things, so down-case term type.
+ Hardly any uppercase letters in terminal types; should be none. */
+ {
+ 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 /* VMS */
+
+ term_init (terminal_type);
+
+ {
+ struct frame *sf = SELECTED_FRAME ();
+ int width = FRAME_TOTAL_COLS (sf);
+ int height = FRAME_LINES (sf);
+
+ unsigned int total_glyphs = height * (width + 2) * sizeof (struct glyph);
+
+ /* If these sizes are so big they cause overflow, just ignore the
+ change. It's not clear what better we could do. */
+ 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 /* CANNOT_DUMP */
+ signal (SIGWINCH, window_change_signal);
+ #endif /* SIGWINCH */
+
+ /* Set up faces of the initial terminal frame of a dumped Emacs. */
+ if (initialized
+ && !noninteractive
+ #ifdef MSDOS
+ /* The MSDOS terminal turns on its ``window system'' relatively
+ late into the startup, so we cannot do the frame faces'
+ initialization just yet. It will be done later by pc-win.el
+ and internal_terminal_init. */
+ && (strcmp (terminal_type, "internal") != 0 || inhibit_window_system)
+ #endif
+ && NILP (Vwindow_system))
+ {
+ /* For the initial frame, we don't have any way of knowing what
+ are the foreground and background colors of the terminal. */
+ 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"));
+ }
+ }
+
+
+
+ /***********************************************************************
+ Blinking cursor
+ ***********************************************************************/
+
+ DEFUN ("internal-show-cursor", Finternal_show_cursor,
+ Sinternal_show_cursor, 2, 2, 0,
+ doc: /* Set the cursor-visibility flag of WINDOW to SHOW.
+ WINDOW nil means use the selected window. SHOW non-nil means
+ show a cursor in WINDOW in the next redisplay. SHOW nil means
+ don't show a cursor. */)
+ (window, show)
+ Lisp_Object window, show;
+ {
+ /* Don't change cursor state while redisplaying. This could confuse
+ output routines. */
+ if (!redisplaying_p)
+ {
+ if (NILP (window))
+ window = selected_window;
+ else
+ CHECK_WINDOW (window);
+
+ XWINDOW (window)->cursor_off_p = NILP (show);
+ }
+
+ return Qnil;
+ }
+
+
+ DEFUN ("internal-show-cursor-p", Finternal_show_cursor_p,
+ Sinternal_show_cursor_p, 0, 1, 0,
+ doc: /* Value is non-nil if next redisplay will display a cursor in
WINDOW.
+ 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);
+
+ w = XWINDOW (window);
+ return w->cursor_off_p ? Qnil : Qt;
+ }
+
+
+ /***********************************************************************
+ Initialization
+ ***********************************************************************/
+
+ 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,
+ doc: /* *The output baud rate of the terminal.
+ On most systems, changing this value will affect the amount of padding
+ and the other strategic decisions made during redisplay. */);
+
+ DEFVAR_BOOL ("inverse-video", &inverse_video,
+ doc: /* *Non-nil means invert the entire frame display.
+ This means everything is in inverse video which otherwise would not be. */);
+
+ DEFVAR_BOOL ("visible-bell", &visible_bell,
+ doc: /* *Non-nil means try to flash the frame to represent a
bell.
+
+ See also `ring-bell-function'. */);
+
+ DEFVAR_BOOL ("no-redraw-on-reenter", &no_redraw_on_reenter,
+ doc: /* *Non-nil means no need to redraw entire frame after
suspending.
+ A non-nil value is useful if the terminal can automatically preserve
+ Emacs's frame display when you reenter Emacs.
+ It is up to you to set this variable if your terminal can do that. */);
+
+ DEFVAR_LISP ("window-system", &Vwindow_system,
+ doc: /* Name of window system that Emacs is displaying through.
+ The value is a symbol--for instance, `x' for X windows.
+ The value is nil if Emacs is using a text-only terminal. */);
+
+ DEFVAR_LISP ("window-system-version", &Vwindow_system_version,
+ doc: /* The version number of the window system in use.
+ For X windows, this is 10 or 11. */);
+
+ DEFVAR_BOOL ("cursor-in-echo-area", &cursor_in_echo_area,
+ doc: /* Non-nil means put cursor in minibuffer, at end of any
message there. */);
+
+ DEFVAR_LISP ("glyph-table", &Vglyph_table,
+ doc: /* Table defining how to output a glyph code to the frame.
+ If not nil, this is a vector indexed by glyph code to define the glyph.
+ Each element can be:
+ integer: a glyph code which this glyph is an alias for.
+ string: output this glyph using that string (not impl. in X windows).
+ nil: this glyph mod 524288 is the code of a character to output,
+ and this glyph / 524288 is the face number (see `face-id') to use
+ while outputting it. */);
+ Vglyph_table = Qnil;
+
+ DEFVAR_LISP ("standard-display-table", &Vstandard_display_table,
+ doc: /* Display table to use for buffers that specify none.
+ See `buffer-display-table' for more information. */);
+ Vstandard_display_table = Qnil;
+
+ DEFVAR_BOOL ("redisplay-dont-pause", &redisplay_dont_pause,
+ doc: /* *Non-nil means update isn't paused when input is
detected. */);
+ redisplay_dont_pause = 0;
+
+ /* Initialize `window-system', unless init_display already decided it. */
+ #ifdef CANNOT_DUMP
+ if (noninteractive)
+ #endif
+ {
+ Vwindow_system = Qnil;
+ Vwindow_system_version = Qnil;
+ }
+ }
- [Emacs-diffs] Changes to emacs/src/dispnew.c [emacs-unicode-2],
Kenichi Handa <=