dispnew.c 57.5 KB
Newer Older
Jim Blandy's avatar
Jim Blandy committed
1
/* Updating of data structures for redisplay.
2 3
   Copyright (C) 1985, 1986, 1987, 1988, 1990,
   1992 Free Software Foundation, Inc.
Jim Blandy's avatar
Jim Blandy committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */


#include <signal.h>

#include "config.h"
#include <stdio.h>
#include <ctype.h>

#include "termchar.h"
#include "termopts.h"
#include "cm.h"
#include "lisp.h"
#include "dispextern.h"
#include "buffer.h"
Jim Blandy's avatar
Jim Blandy committed
34
#include "frame.h"
Jim Blandy's avatar
Jim Blandy committed
35 36 37 38 39
#include "window.h"
#include "commands.h"
#include "disptab.h"
#include "indent.h"

40
#include "systty.h"
Jim Blandy's avatar
Jim Blandy committed
41 42
#include "systime.h"

Jim Blandy's avatar
Jim Blandy committed
43 44 45 46 47 48 49 50 51 52 53 54 55 56
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif	/* HAVE_X_WINDOWS */

#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))

#ifndef PENDING_OUTPUT_COUNT
/* 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.  */
#define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_ptr - (FILE)->_base)
#endif

Jim Blandy's avatar
Jim Blandy committed
57
/* Nonzero upon entry to redisplay means do not assume anything about
Jim Blandy's avatar
Jim Blandy committed
58
   current contents of actual terminal frame; clear and redraw it.  */
Jim Blandy's avatar
Jim Blandy committed
59

Jim Blandy's avatar
Jim Blandy committed
60
int frame_garbaged;
Jim Blandy's avatar
Jim Blandy committed
61 62 63 64 65 66 67 68 69 70

/* 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;

Jim Blandy's avatar
Jim Blandy committed
71
/* Invert the color of the whole frame, at a low level.  */
Jim Blandy's avatar
Jim Blandy committed
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

int inverse_video;

/* Line speed of the terminal.  */

int baud_rate;

/* nil or a symbol naming the window system under which emacs is
   running ('x is the only current possibility).  */

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.  */

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
Jim Blandy's avatar
Jim Blandy committed
100 101 102
   so put cursor on minibuffer after the prompt.
   positive means at end of text in echo area;
   negative means at beginning of line.  */
Jim Blandy's avatar
Jim Blandy committed
103 104
int cursor_in_echo_area;

Jim Blandy's avatar
Jim Blandy committed
105 106
/* The currently selected frame.
   In a single-frame version, this variable always remains 0.  */
Jim Blandy's avatar
Jim Blandy committed
107

Jim Blandy's avatar
Jim Blandy committed
108
FRAME_PTR selected_frame;
Jim Blandy's avatar
Jim Blandy committed
109

Jim Blandy's avatar
Jim Blandy committed
110 111 112 113
/* A frame which is not just a minibuffer, 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 remains 0.  */
FRAME_PTR last_nonminibuf_frame;
Jim Blandy's avatar
Jim Blandy committed
114

Jim Blandy's avatar
Jim Blandy committed
115
/* In a single-frame version, the information that would otherwise
116 117 118 119 120 121
   exist inside frame objects lives in the following structure instead.

   NOTE: the_only_frame is not checked for garbage collection; don't
   store collectable objects in any of its fields!

   You're not/The only frame in town/...  */
Jim Blandy's avatar
Jim Blandy committed
122

Jim Blandy's avatar
Jim Blandy committed
123 124
#ifndef MULTI_FRAME
struct frame the_only_frame;
Jim Blandy's avatar
Jim Blandy committed
125
#endif
Jim Blandy's avatar
Jim Blandy committed
126 127

/* This is a vector, made larger whenever it isn't large enough,
Jim Blandy's avatar
Jim Blandy committed
128 129 130
   which is used inside `update_frame' to hold the old contents
   of the FRAME_PHYS_LINES of the frame being updated.  */
struct frame_glyphs **ophys_lines;
Jim Blandy's avatar
Jim Blandy committed
131 132 133 134 135 136 137 138 139 140 141
/* Length of vector currently allocated.  */
int ophys_lines_length;

FILE *termscript;	/* Stdio stream being used for copy of all output.  */

struct cm Wcm;		/* Structure for info on cursor positioning */

extern short ospeed;	/* Output speed (from sg_ospeed) */

int delayed_size_change;  /* 1 means SIGWINCH happened when not safe.  */

Jim Blandy's avatar
Jim Blandy committed
142
#ifdef MULTI_FRAME
Jim Blandy's avatar
Jim Blandy committed
143

Jim Blandy's avatar
Jim Blandy committed
144 145 146 147
DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0,
  "Clear frame FRAME and output again what is supposed to appear on it.")
  (frame)
     Lisp_Object frame;
Jim Blandy's avatar
Jim Blandy committed
148
{
Jim Blandy's avatar
Jim Blandy committed
149
  FRAME_PTR f;
Jim Blandy's avatar
Jim Blandy committed
150

Jim Blandy's avatar
Jim Blandy committed
151 152 153
  CHECK_LIVE_FRAME (frame, 0);
  f = XFRAME (frame);
  update_begin (f);
Jim Blandy's avatar
Jim Blandy committed
154
  /*  set_terminal_modes (); */
Jim Blandy's avatar
Jim Blandy committed
155
  clear_frame ();
156
  clear_frame_records (f);
Jim Blandy's avatar
Jim Blandy committed
157
  update_end (f);
Jim Blandy's avatar
Jim Blandy committed
158 159 160 161
  fflush (stdout);
  windows_or_buffers_changed++;
  /* Mark all windows as INaccurate,
     so that every window will have its redisplay done.  */
Jim Blandy's avatar
Jim Blandy committed
162 163
  mark_window_display_accurate (FRAME_ROOT_WINDOW (f), 0);
  f->garbaged = 0;
Jim Blandy's avatar
Jim Blandy committed
164 165 166 167
  return Qnil;
}

DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "",
Jim Blandy's avatar
Jim Blandy committed
168
  "Redraw all frames marked as having their images garbled.")
Jim Blandy's avatar
Jim Blandy committed
169 170
  ()
{
Jim Blandy's avatar
Jim Blandy committed
171
  Lisp_Object frame, tail;
Jim Blandy's avatar
Jim Blandy committed
172

Jim Blandy's avatar
Jim Blandy committed
173
  for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
Jim Blandy's avatar
Jim Blandy committed
174
    {
Jim Blandy's avatar
Jim Blandy committed
175 176 177
      frame = XCONS (tail)->car;
      if (XFRAME (frame)->garbaged && XFRAME (frame)->visible)
	Fredraw_frame (frame);
Jim Blandy's avatar
Jim Blandy committed
178 179 180 181
    }
  return Qnil;
}

Jim Blandy's avatar
Jim Blandy committed
182 183
redraw_frame (f)
     FRAME_PTR f;
Jim Blandy's avatar
Jim Blandy committed
184
{
Jim Blandy's avatar
Jim Blandy committed
185 186 187
  Lisp_Object frame;
  XSET (frame, Lisp_Frame, f);
  Fredraw_frame (frame);
Jim Blandy's avatar
Jim Blandy committed
188 189
}

Jim Blandy's avatar
Jim Blandy committed
190
#else /* not MULTI_FRAME */
Jim Blandy's avatar
Jim Blandy committed
191 192 193 194 195 196 197

DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, 0,
  "Clear screen and output again what is supposed to appear on it.")
  ()
{
  update_begin (0);
  set_terminal_modes ();
Jim Blandy's avatar
Jim Blandy committed
198
  clear_frame ();
Jim Blandy's avatar
Jim Blandy committed
199 200
  update_end (0);
  fflush (stdout);
Jim Blandy's avatar
Jim Blandy committed
201
  clear_frame_records (0);
Jim Blandy's avatar
Jim Blandy committed
202 203 204
  windows_or_buffers_changed++;
  /* Mark all windows as INaccurate,
     so that every window will have its redisplay done.  */
205
  mark_window_display_accurate (FRAME_ROOT_WINDOW (0));
Jim Blandy's avatar
Jim Blandy committed
206 207 208
  return Qnil;
}

Jim Blandy's avatar
Jim Blandy committed
209
#endif /* not MULTI_FRAME */
Jim Blandy's avatar
Jim Blandy committed
210

Jim Blandy's avatar
Jim Blandy committed
211 212 213
static struct frame_glyphs *
make_frame_glyphs (frame, empty)
     register FRAME_PTR frame;
Jim Blandy's avatar
Jim Blandy committed
214 215 216
     int empty;
{
  register int i;
Jim Blandy's avatar
Jim Blandy committed
217 218 219 220
  register width = FRAME_WIDTH (frame);
  register height = FRAME_HEIGHT (frame);
  register struct frame_glyphs *new =
    (struct frame_glyphs *) xmalloc (sizeof (struct frame_glyphs));
Jim Blandy's avatar
Jim Blandy committed
221

Jim Blandy's avatar
Jim Blandy committed
222
  SET_GLYPHS_FRAME (new, frame);
Jim Blandy's avatar
Jim Blandy committed
223 224 225 226 227 228 229 230 231 232
  new->height = height;
  new->width = width;
  new->used = (int *) xmalloc (height * sizeof (int));
  new->glyphs = (GLYPH **) xmalloc (height * sizeof (GLYPH *));
  new->highlight = (char *) xmalloc (height * sizeof (char));
  new->enable = (char *) xmalloc (height * sizeof (char));
  bzero (new->enable, height * sizeof (char));
  new->bufp = (int *) xmalloc (height * sizeof (int));

#ifdef HAVE_X_WINDOWS
233
  if (FRAME_X_P (frame))
Jim Blandy's avatar
Jim Blandy committed
234 235 236 237 238
    {
      new->top_left_x = (short *) xmalloc (height * sizeof (short));
      new->top_left_y = (short *) xmalloc (height * sizeof (short));
      new->pix_width = (short *) xmalloc (height * sizeof (short));
      new->pix_height = (short *) xmalloc (height * sizeof (short));
239
      new->max_ascent = (short *) xmalloc (height * sizeof (short));
Jim Blandy's avatar
Jim Blandy committed
240 241 242 243 244 245
    }
#endif

  if (empty)
    {
      /* Make the buffer used by decode_mode_spec.  This buffer is also
Jim Blandy's avatar
Jim Blandy committed
246
         used as temporary storage when updating the frame.  See scroll.c. */
Jim Blandy's avatar
Jim Blandy committed
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
      unsigned int total_glyphs = (width + 2) * sizeof (GLYPH);

      new->total_contents = (GLYPH *) xmalloc (total_glyphs);
      bzero (new->total_contents, total_glyphs);
    }
  else
    {
      unsigned int total_glyphs = height * (width + 2) * sizeof (GLYPH);

      new->total_contents = (GLYPH *) xmalloc (total_glyphs);
      bzero (new->total_contents, total_glyphs);
      for (i = 0; i < height; i++)
	new->glyphs[i] = new->total_contents + i * (width + 2) + 1;
    }

  return new;
}

static void
Jim Blandy's avatar
Jim Blandy committed
266 267 268
free_frame_glyphs (frame, glyphs)
     FRAME_PTR frame;
     struct frame_glyphs *glyphs;
Jim Blandy's avatar
Jim Blandy committed
269 270 271 272 273 274 275 276 277 278 279
{
  if (glyphs->total_contents)
    free (glyphs->total_contents);

  free (glyphs->used);
  free (glyphs->glyphs);
  free (glyphs->highlight);
  free (glyphs->enable);
  free (glyphs->bufp);

#ifdef HAVE_X_WINDOWS
280
  if (FRAME_X_P (frame))
Jim Blandy's avatar
Jim Blandy committed
281 282 283 284 285
    {
      free (glyphs->top_left_x);
      free (glyphs->top_left_y);
      free (glyphs->pix_width);
      free (glyphs->pix_height);
286
      free (glyphs->max_ascent);
Jim Blandy's avatar
Jim Blandy committed
287 288 289 290 291 292 293
    }
#endif

  free (glyphs);
}

static void
Jim Blandy's avatar
Jim Blandy committed
294 295
remake_frame_glyphs (frame)
     FRAME_PTR frame;
Jim Blandy's avatar
Jim Blandy committed
296
{
Jim Blandy's avatar
Jim Blandy committed
297 298 299 300 301 302 303 304 305 306 307
  if (FRAME_CURRENT_GLYPHS (frame))
    free_frame_glyphs (frame, FRAME_CURRENT_GLYPHS (frame));
  if (FRAME_DESIRED_GLYPHS (frame))
    free_frame_glyphs (frame, FRAME_DESIRED_GLYPHS (frame));
  if (FRAME_TEMP_GLYPHS (frame))
    free_frame_glyphs (frame, FRAME_TEMP_GLYPHS (frame));

  if (FRAME_MESSAGE_BUF (frame))
    FRAME_MESSAGE_BUF (frame)
      = (char *) xrealloc (FRAME_MESSAGE_BUF (frame),
			   FRAME_WIDTH (frame) + 1);
Jim Blandy's avatar
Jim Blandy committed
308
  else
Jim Blandy's avatar
Jim Blandy committed
309 310
    FRAME_MESSAGE_BUF (frame)
      = (char *) xmalloc (FRAME_WIDTH (frame) + 1);
Jim Blandy's avatar
Jim Blandy committed
311

Jim Blandy's avatar
Jim Blandy committed
312 313 314 315
  FRAME_CURRENT_GLYPHS (frame) = make_frame_glyphs (frame, 0);
  FRAME_DESIRED_GLYPHS (frame) = make_frame_glyphs (frame, 0);
  FRAME_TEMP_GLYPHS (frame) = make_frame_glyphs (frame, 1);
  SET_FRAME_GARBAGED (frame);
Jim Blandy's avatar
Jim Blandy committed
316 317
}

Jim Blandy's avatar
Jim Blandy committed
318
/* Return the hash code of contents of line VPOS in frame-matrix M.  */
Jim Blandy's avatar
Jim Blandy committed
319 320 321

static int
line_hash_code (m, vpos)
Jim Blandy's avatar
Jim Blandy committed
322
     register struct frame_glyphs *m;
Jim Blandy's avatar
Jim Blandy committed
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
     int vpos;
{
  register GLYPH *body, *end;
  register int h = 0;

  if (!m->enable[vpos])
    return 0;

  /* Give all lighlighted lines the same hash code
     so as to encourage scrolling to leave them in place.  */
  if (m->highlight[vpos])
    return -1;

  body = m->glyphs[vpos];

  if (must_write_spaces)
    while (1)
      {
	GLYPH g = *body++;

	if (g == 0)
	  break;
	h = (((h << 4) + (h >> 24)) & 0x0fffffff) + g - SPACEGLYPH;
      }
  else
    while (1)
      {
	GLYPH g = *body++;

	if (g == 0)
	  break;
	h = (((h << 4) + (h >> 24)) & 0x0fffffff) + g;
      }

  if (h)
    return h;
  return 1;
}

/* Return number of characters in line in M at vpos VPOS,
   except don't count leading and trailing spaces
   unless the terminal requires those to be explicitly output.  */

static unsigned int
line_draw_cost (m, vpos)
Jim Blandy's avatar
Jim Blandy committed
368
     struct frame_glyphs *m;
Jim Blandy's avatar
Jim Blandy committed
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
     int vpos;
{
  register GLYPH *beg = m->glyphs[vpos];
  register GLYPH *end = m->glyphs[vpos] + m->used[vpos];
  register int i;
  register int tlen = GLYPH_TABLE_LENGTH;
  register Lisp_Object *tbase = GLYPH_TABLE_BASE;

  /* Ignore trailing and leading spaces if we can.  */
  if (!must_write_spaces)
    {
      while ((end != beg) && (*end == SPACEGLYPH))
	--end;
      if (end == beg)
	return (0); /* All blank line. */

      while (*beg == SPACEGLYPH)
	++beg;
    }

  /* If we don't have a glyph-table, each glyph is one character,
     so return the number of glyphs.  */
  if (tbase == 0)
    return end - beg;

  /* Otherwise, scan the glyphs and accumulate their total size in I.  */
  i = 0;
  while ((beg <= end) && *beg)
    {
      register GLYPH g = *beg++;

      if (GLYPH_SIMPLE_P (tbase, tlen, g))
	i += 1;
      else
	i += GLYPH_LENGTH (tbase, g);
    }
  return i;
}

/* The functions on this page are the interface from xdisp.c to redisplay.

   The only other interface into redisplay is through setting
Jim Blandy's avatar
Jim Blandy committed
411 412
   FRAME_CURSOR_X (frame) and FRAME_CURSOR_Y (frame)
   and SET_FRAME_GARBAGED (frame).  */
Jim Blandy's avatar
Jim Blandy committed
413 414 415

/* cancel_line eliminates any request to display a line at position `vpos' */

Jim Blandy's avatar
Jim Blandy committed
416
cancel_line (vpos, frame)
Jim Blandy's avatar
Jim Blandy committed
417
     int vpos;
Jim Blandy's avatar
Jim Blandy committed
418
     register FRAME_PTR frame;
Jim Blandy's avatar
Jim Blandy committed
419
{
Jim Blandy's avatar
Jim Blandy committed
420
  FRAME_DESIRED_GLYPHS (frame)->enable[vpos] = 0;
Jim Blandy's avatar
Jim Blandy committed
421 422
}

Jim Blandy's avatar
Jim Blandy committed
423 424
clear_frame_records (frame)
     register FRAME_PTR frame;
Jim Blandy's avatar
Jim Blandy committed
425
{
Jim Blandy's avatar
Jim Blandy committed
426
  bzero (FRAME_CURRENT_GLYPHS (frame)->enable, FRAME_HEIGHT (frame));
Jim Blandy's avatar
Jim Blandy committed
427 428 429 430 431
}

/* Prepare to display on line VPOS starting at HPOS within it.  */

void
Jim Blandy's avatar
Jim Blandy committed
432 433
get_display_line (frame, vpos, hpos)
     register FRAME_PTR frame;
Jim Blandy's avatar
Jim Blandy committed
434 435 436
     int vpos;
     register int hpos;
{
Jim Blandy's avatar
Jim Blandy committed
437 438
  register struct frame_glyphs *glyphs;
  register struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (frame);
Jim Blandy's avatar
Jim Blandy committed
439 440
  register GLYPH *p;

441
  if (vpos < 0)
Jim Blandy's avatar
Jim Blandy committed
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
    abort ();

  if ((desired_glyphs->enable[vpos]) && desired_glyphs->used[vpos] > hpos)
    abort ();

  if (! desired_glyphs->enable[vpos])
    {
      desired_glyphs->used[vpos] = 0;
      desired_glyphs->highlight[vpos] = 0;
      desired_glyphs->enable[vpos] = 1;
    }

  if (hpos > desired_glyphs->used[vpos])
    {
      GLYPH *g = desired_glyphs->glyphs[vpos] + desired_glyphs->used[vpos];
      GLYPH *end = desired_glyphs->glyphs[vpos] + hpos;

      desired_glyphs->used[vpos] = hpos;
      while (g != end)
	*g++ = SPACEGLYPH;
    }
}

/* Like bcopy except never gets confused by overlap.  */

void
safe_bcopy (from, to, size)
     char *from, *to;
     int size;
{
  register char *endf;
  register char *endt;

  if (size == 0)
    return;

  /* If destination is higher in memory, and overlaps source zone,
     copy from the end.  */
  if (from < to && from + size > to)
    {
      endf = from + size;
      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 ever
	 too bad, I'm trying to err in its favor.  */
      if (to - from < 64)
	{
	  do
	    *--endt = *--endf;
	  while (endf != from);
	}
      else
	{
Jim Blandy's avatar
Jim Blandy committed
499 500
	  /* Since TO - FROM >= 64, the overlap is less than SIZE,
	     so we can always safely do this loop once.  */
Jim Blandy's avatar
Jim Blandy committed
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
	  while (endt > to)
	    {
	      endt -= (to - from);
	      endf -= (to - from);

	      bcopy (endf, endt, to - from);
	    }
	  
	  /* If TO - FROM wasn't a multiple of SIZE, 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);
	}
    }
  else
    bcopy (from, to, size);
}     

#if 0
void
safe_bcopy (from, to, size)
     char *from, *to;
     int size;
{
  register char *endf;
  register char *endt;

  if (size == 0)
    return;

  /* If destination is higher in memory, and overlaps source zone,
     copy from the end. */
  if (from < to && from + size > to)
    {
      endf = from + size;
      endt = to + size;

      do
	*--endt = *--endf;
      while (endf != from);

      return;
    }

  bcopy (from, to, size);
}
#endif

Jim Blandy's avatar
Jim Blandy committed
549
/* Rotate a vector of SIZE bytes right, by DISTANCE bytes.
Jim Blandy's avatar
Jim Blandy committed
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
   DISTANCE may be negative.  */

static void
rotate_vector (vector, size, distance)
     char *vector;
     int size;
     int distance;
{
  char *temp = (char *) alloca (size);

  if (distance < 0)
    distance += size;

  bcopy (vector, temp + distance, size - distance);
  bcopy (vector + size - distance, temp, distance);
  bcopy (temp, vector, size);
}

/* Scroll lines from vpos FROM up to but not including vpos END
   down by AMOUNT lines (AMOUNT may be negative).
   Returns nonzero if done, zero if terminal cannot scroll them.  */

int
Jim Blandy's avatar
Jim Blandy committed
573 574
scroll_frame_lines (frame, from, end, amount)
     register FRAME_PTR frame;
Jim Blandy's avatar
Jim Blandy committed
575 576 577
     int from, end, amount;
{
  register int i;
Jim Blandy's avatar
Jim Blandy committed
578 579
  register struct frame_glyphs *current_frame
    = FRAME_CURRENT_GLYPHS (frame);
Jim Blandy's avatar
Jim Blandy committed
580 581 582 583 584 585 586 587 588

  if (!line_ins_del_ok)
    return 0;

  if (amount == 0)
    return 1;

  if (amount > 0)
    {
Jim Blandy's avatar
Jim Blandy committed
589
      update_begin (frame);
Jim Blandy's avatar
Jim Blandy committed
590 591 592 593 594 595
      set_terminal_window (end + amount);
      if (!scroll_region_ok)
	ins_del_lines (end, -amount);
      ins_del_lines (from, amount);
      set_terminal_window (0);

Jim Blandy's avatar
Jim Blandy committed
596
      rotate_vector (current_frame->glyphs + from,
Jim Blandy's avatar
Jim Blandy committed
597 598 599
		     sizeof (GLYPH *) * (end + amount - from),
		     amount * sizeof (GLYPH *));

Jim Blandy's avatar
Jim Blandy committed
600 601 602
      safe_bcopy (current_frame->used + from,
		  current_frame->used + from + amount,
		  (end - from) * sizeof current_frame->used[0]);
Jim Blandy's avatar
Jim Blandy committed
603

Jim Blandy's avatar
Jim Blandy committed
604 605 606
      safe_bcopy (current_frame->highlight + from,
		  current_frame->highlight + from + amount,
		  (end - from) * sizeof current_frame->highlight[0]);
Jim Blandy's avatar
Jim Blandy committed
607

Jim Blandy's avatar
Jim Blandy committed
608 609 610
      safe_bcopy (current_frame->enable + from,
		  current_frame->enable + from + amount,
		  (end - from) * sizeof current_frame->enable[0]);
Jim Blandy's avatar
Jim Blandy committed
611 612 613

      /* Mark the lines made empty by scrolling as enabled, empty and
	 normal video.  */
Jim Blandy's avatar
Jim Blandy committed
614 615 616 617
      bzero (current_frame->used + from,
	     amount * sizeof current_frame->used[0]);
      bzero (current_frame->highlight + from,
	     amount * sizeof current_frame->highlight[0]);
Jim Blandy's avatar
Jim Blandy committed
618 619
      for (i = from; i < from + amount; i++)
	{
Jim Blandy's avatar
Jim Blandy committed
620 621
	  current_frame->glyphs[i][0] = '\0';
	  current_frame->enable[i] = 1;
Jim Blandy's avatar
Jim Blandy committed
622 623
	}

Jim Blandy's avatar
Jim Blandy committed
624 625 626
      safe_bcopy (current_frame->bufp + from,
		  current_frame->bufp + from + amount,
		  (end - from) * sizeof current_frame->bufp[0]);
Jim Blandy's avatar
Jim Blandy committed
627 628

#ifdef HAVE_X_WINDOWS
629
      if (FRAME_X_P (frame))
Jim Blandy's avatar
Jim Blandy committed
630
	{
Jim Blandy's avatar
Jim Blandy committed
631 632 633
	  safe_bcopy (current_frame->top_left_x + from,
		      current_frame->top_left_x + from + amount,
		      (end - from) * sizeof current_frame->top_left_x[0]);
Jim Blandy's avatar
Jim Blandy committed
634

Jim Blandy's avatar
Jim Blandy committed
635 636 637
	  safe_bcopy (current_frame->top_left_y + from,
		      current_frame->top_left_y + from + amount,
		      (end - from) * sizeof current_frame->top_left_y[0]);
Jim Blandy's avatar
Jim Blandy committed
638

Jim Blandy's avatar
Jim Blandy committed
639 640 641
	  safe_bcopy (current_frame->pix_width + from,
		      current_frame->pix_width + from + amount,
		      (end - from) * sizeof current_frame->pix_width[0]);
Jim Blandy's avatar
Jim Blandy committed
642

Jim Blandy's avatar
Jim Blandy committed
643 644 645
	  safe_bcopy (current_frame->pix_height + from,
		      current_frame->pix_height + from + amount,
		      (end - from) * sizeof current_frame->pix_height[0]);
646 647 648 649

	  safe_bcopy (current_frame->max_ascent + from,
		      current_frame->max_ascent + from + amount,
		      (end - from) * sizeof current_frame->max_ascent[0]);
Jim Blandy's avatar
Jim Blandy committed
650 651 652
	}
#endif				/* HAVE_X_WINDOWS */

Jim Blandy's avatar
Jim Blandy committed
653
      update_end (frame);
Jim Blandy's avatar
Jim Blandy committed
654 655 656
    }
  if (amount < 0)
    {
Jim Blandy's avatar
Jim Blandy committed
657
      update_begin (frame);
Jim Blandy's avatar
Jim Blandy committed
658 659 660 661 662 663
      set_terminal_window (end);
      ins_del_lines (from + amount, amount);
      if (!scroll_region_ok)
	ins_del_lines (end + amount, -amount);
      set_terminal_window (0);

Jim Blandy's avatar
Jim Blandy committed
664
      rotate_vector (current_frame->glyphs + from + amount,
Jim Blandy's avatar
Jim Blandy committed
665 666 667
		     sizeof (GLYPH *) * (end - from - amount),
		     amount * sizeof (GLYPH *));

Jim Blandy's avatar
Jim Blandy committed
668 669 670
      safe_bcopy (current_frame->used + from,
		  current_frame->used + from + amount,
		  (end - from) * sizeof current_frame->used[0]);
Jim Blandy's avatar
Jim Blandy committed
671

Jim Blandy's avatar
Jim Blandy committed
672 673 674
      safe_bcopy (current_frame->highlight + from,
		  current_frame->highlight + from + amount,
		  (end - from) * sizeof current_frame->highlight[0]);
Jim Blandy's avatar
Jim Blandy committed
675

Jim Blandy's avatar
Jim Blandy committed
676 677 678
      safe_bcopy (current_frame->enable + from,
		  current_frame->enable + from + amount,
		  (end - from) * sizeof current_frame->enable[0]);
Jim Blandy's avatar
Jim Blandy committed
679 680 681

      /* Mark the lines made empty by scrolling as enabled, empty and
	 normal video.  */
Jim Blandy's avatar
Jim Blandy committed
682 683 684 685
      bzero (current_frame->used + end + amount,
	     - amount * sizeof current_frame->used[0]);
      bzero (current_frame->highlight + end + amount,
	     - amount * sizeof current_frame->highlight[0]);
Jim Blandy's avatar
Jim Blandy committed
686 687
      for (i = end + amount; i < end; i++)
	{
Jim Blandy's avatar
Jim Blandy committed
688 689
	  current_frame->glyphs[i][0] = '\0';
	  current_frame->enable[i] = 1;
Jim Blandy's avatar
Jim Blandy committed
690 691
	}

Jim Blandy's avatar
Jim Blandy committed
692 693 694
      safe_bcopy (current_frame->bufp + from,
		  current_frame->bufp + from + amount,
		  (end - from) * sizeof current_frame->bufp[0]);
Jim Blandy's avatar
Jim Blandy committed
695 696

#ifdef HAVE_X_WINDOWS
697
      if (FRAME_X_P (frame))
Jim Blandy's avatar
Jim Blandy committed
698
	{
Jim Blandy's avatar
Jim Blandy committed
699 700 701
	  safe_bcopy (current_frame->top_left_x + from,
		      current_frame->top_left_x + from + amount,
		      (end - from) * sizeof current_frame->top_left_x[0]);
Jim Blandy's avatar
Jim Blandy committed
702

Jim Blandy's avatar
Jim Blandy committed
703 704 705
	  safe_bcopy (current_frame->top_left_y + from,
		      current_frame->top_left_y + from + amount,
		      (end - from) * sizeof current_frame->top_left_y[0]);
Jim Blandy's avatar
Jim Blandy committed
706

Jim Blandy's avatar
Jim Blandy committed
707 708 709
	  safe_bcopy (current_frame->pix_width + from,
		      current_frame->pix_width + from + amount,
		      (end - from) * sizeof current_frame->pix_width[0]);
Jim Blandy's avatar
Jim Blandy committed
710

Jim Blandy's avatar
Jim Blandy committed
711 712 713
	  safe_bcopy (current_frame->pix_height + from,
		      current_frame->pix_height + from + amount,
		      (end - from) * sizeof current_frame->pix_height[0]);
714 715 716 717

	  safe_bcopy (current_frame->max_ascent + from,
		      current_frame->max_ascent + from + amount,
		      (end - from) * sizeof current_frame->max_ascent[0]);
Jim Blandy's avatar
Jim Blandy committed
718 719 720
	}
#endif				/* HAVE_X_WINDOWS */

Jim Blandy's avatar
Jim Blandy committed
721
      update_end (frame);
Jim Blandy's avatar
Jim Blandy committed
722 723 724 725
    }
  return 1;
}

Jim Blandy's avatar
Jim Blandy committed
726
/* After updating a window W that isn't the full frame wide,
Jim Blandy's avatar
Jim Blandy committed
727
   copy all the columns that W does not occupy
Jim Blandy's avatar
Jim Blandy committed
728 729
   into the FRAME_DESIRED_GLYPHS (frame) from the FRAME_PHYS_GLYPHS (frame)
   so that update_frame will not change those columns.  */
Jim Blandy's avatar
Jim Blandy committed
730 731 732 733 734

preserve_other_columns (w)
     struct window *w;
{
  register int vpos;
Jim Blandy's avatar
Jim Blandy committed
735 736
  register struct frame_glyphs *current_frame, *desired_frame;
  register FRAME_PTR frame = XFRAME (w->frame);
Jim Blandy's avatar
Jim Blandy committed
737 738 739 740
  int start = XFASTINT (w->left);
  int end = XFASTINT (w->left) + XFASTINT (w->width);
  int bot = XFASTINT (w->top) + XFASTINT (w->height);

Jim Blandy's avatar
Jim Blandy committed
741 742
  current_frame = FRAME_CURRENT_GLYPHS (frame);
  desired_frame = FRAME_DESIRED_GLYPHS (frame);
Jim Blandy's avatar
Jim Blandy committed
743 744 745

  for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
    {
Jim Blandy's avatar
Jim Blandy committed
746
      if (current_frame->enable[vpos] && desired_frame->enable[vpos])
Jim Blandy's avatar
Jim Blandy committed
747 748 749 750 751
	{
	  if (start > 0)
	    {
	      int len;

Jim Blandy's avatar
Jim Blandy committed
752 753 754 755 756
	      bcopy (current_frame->glyphs[vpos],
		     desired_frame->glyphs[vpos], start);
	      len = min (start, current_frame->used[vpos]);
	      if (desired_frame->used[vpos] < len)
		desired_frame->used[vpos] = len;
Jim Blandy's avatar
Jim Blandy committed
757
	    }
Jim Blandy's avatar
Jim Blandy committed
758 759
	  if (current_frame->used[vpos] > end
	      && desired_frame->used[vpos] < current_frame->used[vpos])
Jim Blandy's avatar
Jim Blandy committed
760
	    {
Jim Blandy's avatar
Jim Blandy committed
761 762
	      while (desired_frame->used[vpos] < end)
		desired_frame->glyphs[vpos][desired_frame->used[vpos]++]
Jim Blandy's avatar
Jim Blandy committed
763
		  = SPACEGLYPH;
Jim Blandy's avatar
Jim Blandy committed
764 765 766 767
	      bcopy (current_frame->glyphs[vpos] + end,
		     desired_frame->glyphs[vpos] + end,
		     current_frame->used[vpos] - end);
	      desired_frame->used[vpos] = current_frame->used[vpos];
Jim Blandy's avatar
Jim Blandy committed
768 769 770 771 772 773 774
	    }
	}
    }
}

#if 0

Jim Blandy's avatar
Jim Blandy committed
775
/* If window w does not need to be updated and isn't the full frame wide,
Jim Blandy's avatar
Jim Blandy committed
776
 copy all the columns that w does occupy
Jim Blandy's avatar
Jim Blandy committed
777 778
 into the FRAME_DESIRED_LINES (frame) from the FRAME_PHYS_LINES (frame)
 so that update_frame will not change those columns.
Jim Blandy's avatar
Jim Blandy committed
779 780 781 782 783 784 785

 Have not been able to figure out how to use this correctly.  */

preserve_my_columns (w)
     struct window *w;
{
  register int vpos, fin;
Jim Blandy's avatar
Jim Blandy committed
786 787
  register struct frame_glyphs *l1, *l2;
  register FRAME_PTR frame = XFRAME (w->frame);
Jim Blandy's avatar
Jim Blandy committed
788 789 790 791 792 793
  int start = XFASTINT (w->left);
  int end = XFASTINT (w->left) + XFASTINT (w->width);
  int bot = XFASTINT (w->top) + XFASTINT (w->height);

  for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
    {
Jim Blandy's avatar
Jim Blandy committed
794 795
      if ((l1 = FRAME_DESIRED_GLYPHS (frame)->glyphs[vpos + 1])
	  && (l2 = FRAME_PHYS_GLYPHS (frame)->glyphs[vpos + 1]))
Jim Blandy's avatar
Jim Blandy committed
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
	{
	  if (l2->length > start && l1->length < l2->length)
	    {
	      fin = l2->length;
	      if (fin > end) fin = end;
	      while (l1->length < start)
		l1->body[l1->length++] = ' ';
	      bcopy (l2->body + start, l1->body + start, fin - start);
	      l1->length = fin;
	    }
	}
    }
}

#endif

/* On discovering that the redisplay for a window was no good,
   cancel the columns of that window, so that when the window is
   displayed over again get_display_line will not complain.  */

cancel_my_columns (w)
     struct window *w;
{
  register int vpos;
Jim Blandy's avatar
Jim Blandy committed
820 821
  register struct frame_glyphs *desired_glyphs =
    FRAME_DESIRED_GLYPHS (XFRAME (w->frame));
Jim Blandy's avatar
Jim Blandy committed
822 823 824 825 826 827 828 829 830
  register int start = XFASTINT (w->left);
  register int bot = XFASTINT (w->top) + XFASTINT (w->height);

  for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
    if (desired_glyphs->enable[vpos]
	&& desired_glyphs->used[vpos] >= start)
      desired_glyphs->used[vpos] = start;
}

Jim Blandy's avatar
Jim Blandy committed
831
/* These functions try to perform directly and immediately on the frame
Jim Blandy's avatar
Jim Blandy committed
832 833 834
   the necessary output for one change in the buffer.
   They may return 0 meaning nothing was done if anything is difficult,
   or 1 meaning the output was performed properly.
Jim Blandy's avatar
Jim Blandy committed
835
   They assume that the frame was up to date before the buffer
Jim Blandy's avatar
Jim Blandy committed
836 837 838 839 840 841 842
   change being displayed.  THey make various other assumptions too;
   see command_loop_1 where these are called.  */

int
direct_output_for_insert (g)
     int g;
{
Jim Blandy's avatar
Jim Blandy committed
843 844 845
  register FRAME_PTR frame = selected_frame;
  register struct frame_glyphs *current_frame
    = FRAME_CURRENT_GLYPHS (frame);
Jim Blandy's avatar
Jim Blandy committed
846 847 848 849 850 851 852 853

#ifndef COMPILER_REGISTER_BUG
  register
#endif /* COMPILER_REGISTER_BUG */
    struct window *w = XWINDOW (selected_window);
#ifndef COMPILER_REGISTER_BUG
  register
#endif /* COMPILER_REGISTER_BUG */
Jim Blandy's avatar
Jim Blandy committed
854
    int hpos = FRAME_CURSOR_X (frame);
Jim Blandy's avatar
Jim Blandy committed
855 856 857
#ifndef COMPILER_REGISTER_BUG
  register
#endif /* COMPILER_REGISTER_BUG */
Jim Blandy's avatar
Jim Blandy committed
858
    int vpos = FRAME_CURSOR_Y (frame);
Jim Blandy's avatar
Jim Blandy committed
859 860 861 862 863 864 865 866

  /* Give up if about to continue line */
  if (hpos - XFASTINT (w->left) + 1 + 1 >= XFASTINT (w->width)

  /* Avoid losing if cursor is in invisible text off left margin */
      || (XINT (w->hscroll) && hpos == XFASTINT (w->left))
    
  /* Give up if cursor outside window (in minibuf, probably) */
867
      || cursor_in_echo_area
Jim Blandy's avatar
Jim Blandy committed
868 869
      || FRAME_CURSOR_Y (frame) < XFASTINT (w->top)
      || FRAME_CURSOR_Y (frame) >= XFASTINT (w->top) + XFASTINT (w->height)
Jim Blandy's avatar
Jim Blandy committed
870

Jim Blandy's avatar
Jim Blandy committed
871
  /* Give up if cursor not really at FRAME_CURSOR_X, FRAME_CURSOR_Y */
Jim Blandy's avatar
Jim Blandy committed
872 873 874 875 876 877 878 879 880
      || !display_completed

  /* Give up if buffer appears in two places.  */
      || buffer_shared > 1

  /* Give up if w is minibuffer and a message is being displayed there */
      || (MINI_WINDOW_P (w) && echo_area_glyphs))
    return 0;

Jim Blandy's avatar
Jim Blandy committed
881
  current_frame->glyphs[vpos][hpos] = g;
Jim Blandy's avatar
Jim Blandy committed
882 883 884 885 886 887 888
  unchanged_modified = MODIFF;
  beg_unchanged = GPT - BEG;
  XFASTINT (w->last_point) = point;
  XFASTINT (w->last_point_x) = hpos;
  XFASTINT (w->last_modified) = MODIFF;

  reassert_line_highlight (0, vpos);
Jim Blandy's avatar
Jim Blandy committed
889
  write_glyphs (&current_frame->glyphs[vpos][hpos], 1);
Jim Blandy's avatar
Jim Blandy committed
890
  fflush (stdout);
Jim Blandy's avatar
Jim Blandy committed
891 892
  ++FRAME_CURSOR_X (frame);
  if (hpos == current_frame->used[vpos])
Jim Blandy's avatar
Jim Blandy committed
893
    {
Jim Blandy's avatar
Jim Blandy committed
894 895
      current_frame->used[vpos] = hpos + 1;
      current_frame->glyphs[vpos][hpos + 1] = 0;
Jim Blandy's avatar
Jim Blandy committed
896 897 898 899 900 901 902 903 904
    }

  return 1;
}

int
direct_output_forward_char (n)
     int n;
{
Jim Blandy's avatar
Jim Blandy committed
905
  register FRAME_PTR frame = selected_frame;
Jim Blandy's avatar
Jim Blandy committed
906 907
  register struct window *w = XWINDOW (selected_window);

Jim Blandy's avatar
Jim Blandy committed
908 909
  /* Avoid losing if cursor is in invisible text off left margin
     or about to go off either side of window.  */
Jim Blandy's avatar
Jim Blandy committed
910
  if ((FRAME_CURSOR_X (frame) == XFASTINT (w->left)
Jim Blandy's avatar
Jim Blandy committed
911 912
       && (XINT (w->hscroll) || n < 0))
      || (n > 0
Jim Blandy's avatar
Jim Blandy committed
913
	  && (FRAME_CURSOR_X (frame) + 1
Jim Blandy's avatar
Jim Blandy committed
914
	      >= (XFASTINT (w->left) + XFASTINT (w->width)
Jim Blandy's avatar
Jim Blandy committed
915
		  - (XFASTINT (w->width) < FRAME_WIDTH (frame))
916 917
		  - 1)))
      || cursor_in_echo_area)
Jim Blandy's avatar
Jim Blandy committed
918 919
    return 0;

Jim Blandy's avatar
Jim Blandy committed
920 921
  FRAME_CURSOR_X (frame) += n;
  XFASTINT (w->last_point_x) = FRAME_CURSOR_X (frame);
Jim Blandy's avatar
Jim Blandy committed
922
  XFASTINT (w->last_point) = point;
Jim Blandy's avatar
Jim Blandy committed
923
  cursor_to (FRAME_CURSOR_Y (frame), FRAME_CURSOR_X (frame));
Jim Blandy's avatar
Jim Blandy committed
924 925 926 927 928 929
  fflush (stdout);
  return 1;
}

static void update_line ();

Jim Blandy's avatar
Jim Blandy committed
930
/* Update frame F based on the data in FRAME_DESIRED_GLYPHS.
Jim Blandy's avatar
Jim Blandy committed
931 932 933 934
   Value is nonzero if redisplay stopped due to pending input.
   FORCE nonzero means do not stop for pending input.  */

int
Jim Blandy's avatar
Jim Blandy committed
935 936
update_frame (f, force, inhibit_hairy_id)
     FRAME_PTR f;
Jim Blandy's avatar
Jim Blandy committed
937 938 939
     int force;
     int inhibit_hairy_id;
{
Jim Blandy's avatar
Jim Blandy committed
940 941
  register struct frame_glyphs *current_frame = FRAME_CURRENT_GLYPHS (f);
  register struct frame_glyphs *desired_frame = FRAME_DESIRED_GLYPHS (f);
Jim Blandy's avatar
Jim Blandy committed
942 943 944 945 946 947 948 949
  register int i;
  int pause;
  int preempt_count = baud_rate / 2400 + 1;
  extern input_pending;
#ifdef HAVE_X_WINDOWS
  register int downto, leftmost;
#endif

Jim Blandy's avatar
Jim Blandy committed
950
  if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
Jim Blandy's avatar
Jim Blandy committed
951 952 953 954 955 956 957 958

  detect_input_pending ();
  if (input_pending && !force)
    {
      pause = 1;
      goto do_pause;
    }

Jim Blandy's avatar
Jim Blandy committed
959
  update_begin (f);
Jim Blandy's avatar
Jim Blandy committed
960 961 962 963

  if (!line_ins_del_ok)
    inhibit_hairy_id = 1;

Jim Blandy's avatar
Jim Blandy committed
964 965
  /* See if any of the desired lines are enabled; don't compute for
     i/d line if just want cursor motion. */
Jim Blandy's avatar
Jim Blandy committed
966 967
  for (i = 0; i < FRAME_HEIGHT (f); i++)
    if (desired_frame->enable[i])
Jim Blandy's avatar
Jim Blandy committed
968 969 970
      break;

  /* Try doing i/d line, if not yet inhibited.  */
Jim Blandy's avatar
Jim Blandy committed
971 972
  if (!inhibit_hairy_id && i < FRAME_HEIGHT (f))
    force |= scrolling (f);
Jim Blandy's avatar
Jim Blandy committed
973 974 975

  /* Update the individual lines as needed.  Do bottom line first.  */

Jim Blandy's avatar
Jim Blandy committed
976 977
  if (desired_frame->enable[FRAME_HEIGHT (f) - 1])
    update_line (f, FRAME_HEIGHT (f) - 1);
Jim Blandy's avatar
Jim Blandy committed
978 979

#ifdef HAVE_X_WINDOWS
980
  if (FRAME_X_P (f))
Jim Blandy's avatar
Jim Blandy committed
981
    {
Jim Blandy's avatar
Jim Blandy committed
982 983
      leftmost = downto = f->display.x->internal_border_width;
      if (desired_frame->enable[0])
Jim Blandy's avatar
Jim Blandy committed
984
	{
Jim Blandy's avatar
Jim Blandy committed
985 986 987
	  current_frame->top_left_x[FRAME_HEIGHT (f) - 1] = leftmost;
	  current_frame->top_left_y[FRAME_HEIGHT (f) - 1]
	    = PIXEL_HEIGHT (f) - f->display.x->internal_border_width
988
	      - current_frame->pix_height[FRAME_HEIGHT (f) - 1];
Jim Blandy's avatar
Jim Blandy committed
989 990
	  current_frame->top_left_x[0] = leftmost;
	  current_frame->top_left_y[0] = downto;
Jim Blandy's avatar
Jim Blandy committed
991 992 993 994 995
	}
    }
#endif /* HAVE_X_WINDOWS */

  /* Now update the rest of the lines. */
Jim Blandy's avatar
Jim Blandy committed
996
  for (i = 0; i < FRAME_HEIGHT (f) - 1 && (force || !input_pending); i++)
Jim Blandy's avatar
Jim Blandy committed
997
    {
Jim Blandy's avatar
Jim Blandy committed
998
      if (desired_frame->enable[i])
Jim Blandy's avatar
Jim Blandy committed
999
	{
1000
	  if (FRAME_TERMCAP_P (f))
Jim Blandy's avatar
Jim Blandy committed
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
	    {
	      /* 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)
		    {
Jim Blandy's avatar
Jim Blandy committed
1013 1014
#ifdef EMACS_OUTQSIZE
		      if (EMACS_OUTQSIZE (0, &outq) < 0)
Jim Blandy's avatar
Jim Blandy committed
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
			/* Probably not a tty.  Ignore the error and reset
			 * the outq count. */
			outq = PENDING_OUTPUT_COUNT (stdout);
#endif
		      outq *= 10;
		      sleep (outq / baud_rate);
		    }
		}
	      if ((i - 1) % preempt_count == 0)
		detect_input_pending ();
	    }

Jim Blandy's avatar
Jim Blandy committed
1027
	  update_line (f, i);
Jim Blandy's avatar
Jim Blandy committed
1028
#ifdef HAVE_X_WINDOWS
1029
	  if (FRAME_X_P (f))
Jim Blandy's avatar
Jim Blandy committed
1030
	    {
Jim Blandy's avatar
Jim Blandy committed
1031 1032
	      current_frame->top_left_y[i] = downto;
	      current_frame->top_left_x[i] = leftmost;
Jim Blandy's avatar
Jim Blandy committed
1033 1034 1035 1036
	    }
#endif /* HAVE_X_WINDOWS */
	}

Jim Blandy's avatar
Jim Blandy committed
1037
#ifdef HAVE_X_WINDOWS
1038
      if (FRAME_X_P (f))
1039
	downto += current_frame->pix_height[i];
Jim Blandy's avatar
Jim Blandy committed
1040
#endif
Jim Blandy's avatar
Jim Blandy committed
1041
    }
Jim Blandy's avatar
Jim Blandy committed
1042
  pause = (i < FRAME_HEIGHT (f) - 1) ? i : 0;
Jim Blandy's avatar
Jim Blandy committed
1043 1044 1045 1046

  /* Now just clean up termcap drivers and set cursor, etc.  */
  if (!pause)
    {
1047 1048
      if (cursor_in_echo_area
	  && FRAME_HAS_MINIBUF_P (f))
Jim Blandy's avatar
Jim Blandy committed
1049
	{
1050 1051 1052 1053 1054 1055 1056 1057
	  int top = XINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top);
	  int row, col;

	  if (cursor_in_echo_area < 0)
	    {
	      row = top;
	      col = 0;
	    }
Jim Blandy's avatar
Jim Blandy committed
1058
	  else
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
	    {
	      /* If the minibuffer is several lines high, find the last
		 line that has any text on it.  */
	      row = FRAME_HEIGHT (f);
	      do 
		{
		  row--;
		  if (current_frame->enable[row])
		    col = current_frame->used[row];
		  else
		    col = 0;
		}
	      while (row > top && col == 0);

	      if (col >= FRAME_WIDTH (f))
		{
		  col = 0;
		  if (row < FRAME_HEIGHT (f) - 1)
		    row++;
		}
	    }

	  cursor_to (row, col);
Jim Blandy's avatar
Jim Blandy committed
1082
	}
Jim Blandy's avatar
Jim Blandy committed
1083
      else
Jim Blandy's avatar
Jim Blandy committed
1084 1085
	cursor_to (FRAME_CURSOR_Y (f), max (min (FRAME_CURSOR_X (f),
						  FRAME_WIDTH (f) - 1), 0));
Jim Blandy's avatar
Jim Blandy committed
1086 1087
    }

Jim Blandy's avatar
Jim Blandy committed
1088
  update_end (f);
Jim Blandy's avatar
Jim Blandy committed
1089 1090 1091 1092 1093 1094 1095 1096

  if (termscript)
    fflush (termscript);
  fflush (stdout);

  /* Here if output is preempted because input is detected.  */
 do_pause:

Jim Blandy's avatar
Jim Blandy committed
1097
  if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
Jim Blandy's avatar
Jim Blandy committed
1098 1099
  display_completed = !pause;

Jim Blandy's avatar
Jim Blandy committed
1100
  bzero (desired_frame->enable, FRAME_HEIGHT (f));
Jim Blandy's avatar
Jim Blandy committed
1101 1102 1103 1104 1105 1106 1107 1108 1109
  return pause;
}

/* Called when about to quit, to check for doing so
   at an improper time.  */

void
quit_error_check ()
{
Jim Blandy's avatar
Jim Blandy committed
1110
  if (FRAME_DESIRED_GLYPHS (selected_frame) == 0)
Jim Blandy's avatar
Jim Blandy committed
1111
    return;
Jim Blandy's avatar
Jim Blandy committed
1112
  if (FRAME_DESIRED_GLYPHS (selected_frame)->enable[0])
Jim Blandy's avatar
Jim Blandy committed
1113
    abort ();
Jim Blandy's avatar
Jim Blandy committed
1114
  if (FRAME_DESIRED_GLYPHS (selected_frame)->enable[FRAME_HEIGHT (selected_frame) - 1])
Jim Blandy's avatar
Jim Blandy committed
1115 1116 1117 1118 1119 1120 1121
    abort ();
}

/* Decide what insert/delete line to do, and do it */

extern void scrolling_1 ();

Jim Blandy's avatar
Jim Blandy committed
1122 1123
scrolling (frame)
     FRAME_PTR frame;
Jim Blandy's avatar
Jim Blandy committed
1124 1125 1126 1127
{
  int unchanged_at_top, unchanged_at_bottom;
  int window_size;
  int changed_lines;
Jim Blandy's avatar
Jim Blandy committed
1128 1129 1130
  int *old_hash = (int *) alloca (FRAME_HEIGHT (frame) * sizeof (int));
  int *new_hash = (int *) alloca (FRAME_HEIGHT (frame) * sizeof (int));
  int *draw_cost = (int *) alloca (FRAME_HEIGHT (frame) * sizeof (int));
Jim Blandy's avatar
Jim Blandy committed
1131
  register int i;
Jim Blandy's avatar
Jim Blandy committed
1132 1133 1134
  int free_at_end_vpos = FRAME_HEIGHT (frame);
  register struct frame_glyphs *current_frame = FRAME_CURRENT_GLYPHS (frame);
  register struct frame_glyphs *desired_frame = FRAME_DESIRED_GLYPHS (frame);
Jim Blandy's avatar
Jim Blandy committed
1135 1136 1137 1138 1139 1140 1141 1142

  /* 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;
Jim Blandy's avatar
Jim Blandy committed
1143 1144
  unchanged_at_bottom = FRAME_HEIGHT (frame);
  for (i = 0; i < FRAME_HEIGHT (frame); i++)
Jim Blandy's avatar
Jim Blandy committed
1145 1146
    {
      /* Give up on this scrolling if some old lines are not enabled.  */
Jim Blandy's avatar
Jim Blandy committed
1147
      if (!current_frame->enable[i])
Jim Blandy's avatar
Jim Blandy committed
1148
	return 0;
Jim Blandy's avatar
Jim Blandy committed
1149 1150
      old_hash[i] = line_hash_code (current_frame, i);
      if (! desired_frame->enable[i])
Jim Blandy's avatar
Jim Blandy committed
1151 1152
	new_hash[i] = old_hash[i];
      else
Jim Blandy's avatar
Jim Blandy committed
1153
	new_hash[i] =