1: /* Newly written part of redisplay code.
   2:    Copyright (C) 1985 Richard M. Stallman.
   3: 
   4: This file is part of GNU Emacs.
   5: 
   6: GNU Emacs is distributed in the hope that it will be useful,
   7: but WITHOUT ANY WARRANTY.  No author or distributor
   8: accepts responsibility to anyone for the consequences of using it
   9: or for whether it serves any particular purpose or works at all,
  10: unless he says so in writing.  Refer to the GNU Emacs General Public
  11: License for full details.
  12: 
  13: Everyone is granted permission to copy, modify and redistribute
  14: GNU Emacs, but only under the conditions described in the
  15: GNU Emacs General Public License.   A copy of this license is
  16: supposed to have been given to you along with GNU Emacs so you
  17: can know your rights and responsibilities.  It should be in a
  18: file named COPYING.  Among other things, the copyright notice
  19: and this notice must be preserved on all copies.  */
  20: 
  21: 
  22: #include <signal.h>
  23: 
  24: #include "config.h"
  25: #include <stdio.h>
  26: 
  27: #ifdef HAVE_TIMEVAL
  28: #ifdef HPUX
  29: #include <time.h>
  30: #else
  31: #include <sys/time.h>
  32: #endif
  33: #endif
  34: 
  35: #ifdef USG
  36: #include <termio.h>
  37: #else /* not USG */
  38: #include <sys/ioctl.h>
  39: #endif /* not USG */
  40: 
  41: #undef NULL
  42: 
  43: #include "termchar.h"
  44: #include "termopts.h"
  45: #include "cm.h"
  46: #include "dispextern.h"
  47: #include "lisp.h"
  48: #include "buffer.h"
  49: #include "window.h"
  50: #include "commands.h"
  51: 
  52: #define max(a, b) ((a) > (b) ? (a) : (b))
  53: #define min(a, b) ((a) < (b) ? (a) : (b))
  54: 
  55: /* Nonzero means do not assume anything about current
  56:  contents of actual terminal screen */
  57: 
  58: int screen_garbaged;
  59: 
  60: /* Desired terminal cursor position (to show position of point),
  61:  origin zero */
  62: 
  63: int cursX, cursY;
  64: 
  65: /* Nonzero means last display completed and cursor is really at cursX, cursY.
  66:  Zero means it was preempted. */
  67: 
  68: int display_completed;
  69: 
  70: int visible_bell;   /* If true and the terminal will support it
  71: 			   then the screen will flash instead of
  72: 			   feeping when an error occurs */
  73: int inverse_video;  /* If true and the terminal will support it
  74: 			   then we will use inverse video */
  75: 
  76: int baud_rate;      /* Terminal speed, so we can calculate
  77: 			   the number of characters required to
  78: 			   make the cursor sit still for n secs. */
  79: 
  80: /* the current (physical) screen */
  81: struct display_line *PhysScreen[MScreenLength + 1];
  82: 
  83: /* temporary Copy of PhysScreen made in update_screen */
  84: struct display_line *OPhysScreen[MScreenLength + 1];
  85: 
  86: /* the desired (virtual) screen */
  87: struct display_line *DesiredScreen[MScreenLength + 1];
  88: 
  89: /* Record here all the display line objects, for debugging.  */
  90: static struct display_line *all_lines[2 * MScreenLength];
  91: 
  92: FILE *termscript;   /* Stdio stream being used for copy of all kbdinput.  */
  93: 
  94: struct cm Wcm;      /* Structure for info on cursor positioning */
  95: 
  96: extern short ospeed;    /* Output speed (from sg_ospeed) */
  97: 
  98: /* Use these to chain together free lines */
  99: 
 100: #define LINE_NEXT(l) (*(struct display_line **) l)
 101: #define SET_LINE_NEXT(l, next) (*((struct display_line **) l) = next)
 102: 
 103: /* Chain of free display_line structures, chained thru LINE_NEXT.  */
 104: 
 105: struct display_line *free_display_lines;
 106: 
 107: /* Number of lines now free.  */
 108: 
 109: int free_line_count;
 110: 
 111: /* Allocate as many display_line structures
 112:    as we are ever supposed to need.
 113:    Called at startup, and also if screen size is changed.  */
 114: 
 115: make_display_lines ()
 116: {
 117:   register int i;
 118:   register struct display_line *p, *p1;
 119: 
 120:   /* First, free any that are already allocated */
 121: 
 122:   for (p = free_display_lines; p;)
 123:     {
 124:       p1 = p;
 125:       p = LINE_NEXT (p);
 126:       free (p1);
 127:     }
 128:   free_display_lines = 0;
 129:   free_line_count = 0;
 130: 
 131:   for (i = 0; i <= MScreenLength; i++)
 132:     if (PhysScreen[i])
 133:       {
 134:     free (PhysScreen[i]);
 135:     PhysScreen[i] = 0;
 136:       }
 137: 
 138:   screen_garbaged = 1;
 139: 
 140:   /* Now allocate as many as we can possibly validly need */
 141: 
 142:   for (i = - screen_height; i < screen_height; i++)
 143:     {
 144:       p = (struct display_line *) malloc (sizeof (struct display_line) + screen_width - MScreenWidth);
 145:       if (!p) abort ();
 146:       SET_LINE_NEXT (p, free_display_lines);
 147:       free_display_lines = p;
 148:       all_lines[i + screen_height] = p;
 149:     }
 150:   free_line_count = 2 * screen_height;
 151: }
 152: 
 153: /* Get one of the previously malloc'd display_line structures
 154:    from the free pool.  */
 155: 
 156: struct display_line *
 157: new_display_line ()
 158: {
 159:   register struct display_line *p = free_display_lines;
 160:   /* If we ever use up all the display lines that have been
 161:      allocated, it indicates a bug, since we are supposed
 162:      to need at most two for each line on the screen.  */
 163:   if (!p)
 164:     abort ();
 165:   free_display_lines = LINE_NEXT (p);
 166: 
 167:   bzero (p, p->body - (char *) p);
 168:   SET_LINE_NEXT (p, (struct display_line *)1);  /* Mark as in use.  */
 169:   free_line_count--;
 170:   return p;
 171: }
 172: 
 173: /* Put a display_line back in the free pool.  */
 174: 
 175: return_display_line (p)
 176:      struct display_line *p;
 177: {
 178:   if (!p)
 179:     return;
 180:   if ((int) LINE_NEXT (p) != 1)
 181:     abort ();           /* Already free.  */
 182:   SET_LINE_NEXT (p, free_display_lines);
 183:   free_display_lines = p;
 184:   free_line_count++;
 185: }
 186: 
 187: clear_screen_records ()
 188: {
 189:   register int i;
 190:   for (i = 1; i <= screen_height; i++)
 191:     if (PhysScreen[i])
 192:       return_display_line (PhysScreen[i]);
 193:   bzero (PhysScreen, (screen_height + 1) * sizeof PhysScreen[0]);
 194: }
 195: 
 196: /* Return the hash code of display_line p.  */
 197: line_hash_code (p)
 198:      register struct display_line *p;
 199: {
 200:   register char *body, *end;
 201:   register int h = 0;
 202:   if (!p)
 203:     return 0;
 204:   /* Give all lighlighted lines the same hash code
 205:      so as to encourage scrolling to leave them in place.  */
 206:   if (p->highlighted)
 207:     return -1;
 208: 
 209:   body = p->body;
 210:   end = body + p->length;
 211:   *end = 0;
 212:   if (!must_write_spaces)
 213:     {
 214:       while (*body++ == ' ');
 215:       body--;
 216:       if (body == end)
 217:     return 1;
 218:       while (end[-1] == ' ') end--;
 219:     }
 220:   while (body != end)
 221:     h = (h << 5) + h + *body++;
 222:   if (h)
 223:     return h;
 224:   return 1;
 225: }
 226: 
 227: /* Return number of characters in display_line p,
 228:    except don't count leading and trailing spaces
 229:    unless the terminal requires those to be explicitly output.  */
 230: 
 231: line_draw_cost (p)
 232:      struct display_line *p;
 233: {
 234:   register char *body;
 235:   register int i;
 236: 
 237:   if (!p)
 238:     return 0;
 239: 
 240:   if (must_write_spaces)
 241:     return p->length;
 242: 
 243:   body = p->body - 1;
 244:   for (i = p->length; i > 0 && body[i - 1] == ' '; i--);
 245: 
 246:   i -= count_blanks (p->body);
 247:   return max (i, 0);
 248: }
 249: 
 250: /* The functions on this page are the interface from xdisp.c to redisplay.
 251:  They take cursor position arguments in origin 0.
 252: 
 253:  The only other interface into redisplay is through setting
 254:  cursX and cursY (in xdisp.c) and setting screen_garbaged. */
 255: 
 256: /* cancel_line eliminates any request to display a line at position `vpos' */
 257: 
 258: cancel_line (vpos)
 259:      int vpos;
 260: {
 261:   return_display_line (DesiredScreen[vpos + 1]);
 262:   DesiredScreen[vpos + 1] = 0;
 263: }
 264: 
 265: /* Get a display_line for displaying on line `vpos'
 266:  and set it up for outputting starting at `hpos' within it.  */
 267: 
 268: struct display_line *
 269: get_display_line (vpos, hpos)
 270:      int vpos;
 271:      register int hpos;
 272: {
 273:   register struct display_line *line;
 274:   register char *p;
 275: 
 276:   if (vpos < 0) abort ();
 277: 
 278:   line = DesiredScreen[vpos + 1];
 279:   if (line && line->length > hpos)
 280:     abort ();
 281:   if (!line)
 282:     line = new_display_line ();
 283: 
 284:   if (hpos > line->length)
 285:     {
 286:       p = line->body + line->length;
 287:       hpos -= line->length;
 288:       line->length += hpos;
 289:       while (--hpos >= 0)
 290:     *p++ = ' ';
 291:     }
 292: 
 293:   DesiredScreen[vpos + 1] = line;
 294: 
 295:   return line;
 296: }
 297: 
 298: /* Scroll lines from vpos `from' up to but not including vpos `end'
 299:  down by `amount' lines (`amount' may be negative).
 300:  Returns nonzero if done, zero if terminal cannot scroll them. */
 301: 
 302: int
 303: scroll_screen_lines (from, end, amount)
 304:      int from, end, amount;
 305: {
 306:   register int i;
 307: 
 308:   if (!line_ins_del_ok)
 309:     return 0;
 310: 
 311:   if (amount == 0)
 312:     return 1;
 313:   if (amount > 0)
 314:     {
 315:       set_terminal_window (end + amount);
 316:       if (!scroll_region_ok)
 317:     ins_del_lines (end, -amount);
 318:       ins_del_lines (from, amount);
 319:       set_terminal_window (0);
 320: 
 321:       for (i = end + amount; i >= end + 1; i--)
 322:     return_display_line (PhysScreen[i]);
 323:       for (i = end; i >= from + 1; i--)
 324:     PhysScreen[i + amount] = PhysScreen[i];
 325:       for (i = from + amount; i >= from + 1; i--)
 326:     PhysScreen[i] = 0;
 327:     }
 328:   if (amount < 0)
 329:     {
 330:       set_terminal_window (end);
 331:       ins_del_lines (from + amount, amount);
 332:       if (!scroll_region_ok)
 333:     ins_del_lines (end + amount, -amount);
 334:       set_terminal_window (0);
 335: 
 336:       for (i = from + amount + 1; i <= from; i++)
 337:     return_display_line (PhysScreen[i]);
 338:       for (i = from + 1; i <= end ; i++)
 339:     PhysScreen[i + amount] = PhysScreen[i];
 340:       for (i = end + amount + 1; i <= end; i++)
 341:     PhysScreen[i] = 0;
 342:     }
 343:   return 1;
 344: }
 345: 
 346: /* After updating a window w that isn't the full screen wide,
 347:  copy all the columns that w does not occupy
 348:  into the DesiredScreen lines from the PhysScreen lines
 349:  so that update_screen will not change those columns.  */
 350: 
 351: preserve_other_columns (w)
 352:      struct window *w;
 353: {
 354:   register int vpos;
 355:   register struct display_line *l1, *l2;
 356:   int start = XFASTINT (w->left);
 357:   int end = XFASTINT (w->left) + XFASTINT (w->width);
 358:   int bot = XFASTINT (w->top) + XFASTINT (w->height);
 359: 
 360:   for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
 361:     {
 362:       if ((l1 = DesiredScreen[vpos + 1])
 363:       && (l2 = PhysScreen[vpos + 1]))
 364:     {
 365:       if (start > 0)
 366:         {
 367:           bcopy (l2->body, l1->body, start);
 368:           if (l1->length < start && l1->length < l2->length)
 369:         l1->length = min (start, l2->length);
 370:         }
 371:       if (l2->length > end && l1->length < l2->length)
 372:         {
 373:           while (l1->length < end)
 374:         l1->body[l1->length++] = ' ';
 375:           bcopy (l2->body + end, l1->body + end, l2->length - end);
 376:           l1->length = l2->length;
 377:         }
 378:     }
 379:     }
 380: }
 381: 
 382: #ifdef NOTDEF
 383: 
 384: /* If window w does not need to be updated and isn't the full screen wide,
 385:  copy all the columns that w does occupy
 386:  into the DesiredScreen lines from the PhysScreen lines
 387:  so that update_screen will not change those columns.
 388: 
 389:  Have not been able to figure out how to use this correctly.  */
 390: 
 391: preserve_my_columns (w)
 392:      struct window *w;
 393: {
 394:   register int vpos, fin;
 395:   register struct display_line *l1, *l2;
 396:   int start = XFASTINT (w->left);
 397:   int end = XFASTINT (w->left) + XFASTINT (w->width);
 398:   int bot = XFASTINT (w->top) + XFASTINT (w->height);
 399: 
 400:   for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
 401:     {
 402:       if ((l1 = DesiredScreen[vpos + 1])
 403:       && (l2 = PhysScreen[vpos + 1]))
 404:     {
 405:       if (l2->length > start && l1->length < l2->length)
 406:         {
 407:           fin = l2->length;
 408:           if (fin > end) fin = end;
 409:           while (l1->length < start)
 410:         l1->body[l1->length++] = ' ';
 411:           bcopy (l2->body + start, l1->body + start, fin - start);
 412:           l1->length = fin;
 413:         }
 414:     }
 415:     }
 416: }
 417: 
 418: #endif /* NOTDEF */
 419: 
 420: /* On discovering that the redisplay for a window was no good,
 421:  cancel the columns of that window,
 422:  so that when the window is displayed over again
 423:  get_display_line will not complain. */
 424: 
 425: cancel_my_columns (w)
 426:      struct window *w;
 427: {
 428:   register int vpos;
 429:   register struct display_line *l;
 430:   register int start = XFASTINT (w->left);
 431:   register int bot = XFASTINT (w->top) + XFASTINT (w->height);
 432: 
 433:   for (vpos = XFASTINT (w->top); vpos < bot; vpos++)
 434:     {
 435:       if ((l = DesiredScreen[vpos + 1])
 436:       && l->length >= start)
 437:     l->length = start;
 438:     }
 439: }
 440: 
 441: direct_output_for_insert (c)
 442:      int c;
 443: {
 444:   register struct display_line *p = PhysScreen[cursY + 1];
 445: #ifndef COMPILER_REGISTER_BUG
 446:   register
 447: #endif COMPILER_REGISTER_BUG
 448:     struct window *w = XWINDOW (selected_window);
 449: #ifndef COMPILER_REGISTER_BUG
 450:   register
 451: #endif COMPILER_REGISTER_BUG
 452:     int hpos = cursX;
 453: 
 454:   /* Give up if about to continue line */
 455:   if (hpos - XFASTINT (w->left) + 1 + 1 >= XFASTINT (w->width))
 456:     return;
 457: 
 458:   /* Avoid losing if cursor is in invisible text off left margin */
 459:   if (XINT (w->hscroll) && hpos == XFASTINT (w->left))
 460:     return;
 461: 
 462:   /* Give up if cursor outside window (in minibuf, probably) */
 463:   if (cursY < XFASTINT (w->top)
 464:       || cursY >= XFASTINT (w->top) + XFASTINT (w->height))
 465:     return;
 466: 
 467:   /* Give up if cursor not really at cursX, cursY */
 468:   if (!display_completed)
 469:     return;
 470: 
 471:   /* Give up if w is minibuffer and a message is being displayed there */
 472:   if (EQ (selected_window, minibuf_window) && minibuf_message)
 473:     return;
 474: 
 475:   p->body[hpos] = c;
 476:   unchanged_modified = bf_modified;
 477:   beg_unchanged = bf_s1;
 478:   XFASTINT (w->last_point) = point;
 479:   XFASTINT (w->last_point_x) = cursX;
 480:   XFASTINT (w->last_modified) = bf_modified;
 481: 
 482:   reassert_line_highlight (0, cursY);
 483:   write_chars (p->body + hpos, 1);
 484:   fflush (stdout);
 485:   ++cursX;
 486:   p->length = max (p->length, cursX);
 487:   p->body[p->length] = 0;
 488: }
 489: 
 490: direct_output_forward_char (n)
 491:      int n;
 492: {
 493:   register struct window *w = XWINDOW (selected_window);
 494: 
 495:   /* Avoid losing if cursor is in invisible text off left margin */
 496:   if (XINT (w->hscroll) && cursX == XFASTINT (w->left))
 497:     return;
 498: 
 499:   cursX += n;
 500:   XFASTINT (w->last_point_x) = cursX;
 501:   XFASTINT (w->last_point) = point;
 502:   topos (cursY, cursX);
 503:   fflush (stdout);
 504: }
 505: 
 506: /* At the time this function is called,
 507:  no line is common to PhysScreen and DesiredScreen.
 508:  That is true again when this function returns. */
 509: 
 510: /* `force' nonzero means do not stop for pending input */
 511: 
 512: /* Value is nonzero if redisplay stopped due to pending input */
 513: update_screen (force, inhibit_hairy_id)
 514:      int force;
 515:      int inhibit_hairy_id;
 516: {
 517:     register struct display_line **p;
 518:     register struct display_line *l, *lnew;
 519:     register int i;
 520:     int pause;
 521:     int preempt_count;
 522:     int outq;
 523:     extern input_pending;
 524: 
 525:     if (screen_height == 0) abort (); /* Some bug zeros some core */
 526: 
 527:     bcopy (PhysScreen, OPhysScreen, sizeof PhysScreen);
 528: 
 529:     detect_input_pending ();
 530:     if (input_pending && !force)
 531:       {
 532:     pause = 1;
 533:     goto do_pause;
 534:       }
 535: 
 536:     update_begin ();
 537: 
 538:     if (!line_ins_del_ok)
 539:       inhibit_hairy_id = 1;
 540: 
 541:     /* Don't compute for i/d line if just want cursor motion. */
 542:     for (p = &DesiredScreen[screen_height]; p != DesiredScreen && *p == 0; p--);
 543: 
 544:     /* Try doing i/d line, if not yet inhibited.  */
 545:     if (!inhibit_hairy_id && p != DesiredScreen)
 546:       force |= scrolling ();
 547: 
 548:     /* Update the individual lines as needed.  Do bottom line first.  */
 549: 
 550:     l = DesiredScreen[screen_height];
 551:     if (l && l != PhysScreen[screen_height])
 552:       update_line (PhysScreen[screen_height], l, screen_height - 1);
 553:     preempt_count = baud_rate / 2400;
 554:     for (i = 1; i < screen_height && (force || !input_pending); i++)
 555:       {
 556:     l = PhysScreen[i];
 557:     lnew = DesiredScreen[i];
 558:     if (lnew && lnew != l)
 559:       {
 560:         /* Flush out every so many lines.
 561: 	       Also flush out if likely to have more than 1k buffered otherwise.
 562: 	       I'm told that telnet connections get really screwed by more
 563: 	       than 1k output at once.  */
 564:         outq = stdout->_ptr - stdout->_base;
 565:         if (outq > ((--preempt_count < 0) ? 20 : 900))
 566:           {
 567:         fflush (stdout);
 568:         if (baud_rate < 2400)
 569:           {
 570: #ifdef TIOCOUTQ
 571:             if (ioctl (0, TIOCOUTQ, &outq) < 0)
 572:               /* Probably not a tty.  Ignore the error and reset
 573: 		       * the outq count. */
 574:               outq = stdout->_ptr - stdout->_base;
 575: #endif
 576:             outq *= 10;
 577:             outq /= baud_rate;  /* outq is now in seconds */
 578:             if (outq)
 579:               sleep (outq);
 580:           }
 581:         detect_input_pending ();
 582: 
 583:         preempt_count = baud_rate / 2400;
 584:           }
 585:         /* Now update this line.  */
 586:         update_line (l, lnew, i - 1);
 587:       }
 588:       }
 589:     pause = (i < screen_height) ? i : 0;
 590: 
 591:     /* Now just clean up termcap drivers and set cursor, etc.  */
 592:     if (!pause)
 593:       topos (cursY, max (min (cursX, screen_width - 1), 0));
 594: 
 595:     update_end ();
 596: 
 597:     if (termscript)
 598:       fflush (termscript);
 599:     fflush (stdout);
 600: 
 601:   do_pause:
 602:     if (screen_height == 0) abort (); /* Some bug zeros some core */
 603:     display_completed = !pause;
 604:     /* Free any lines still in desired screen but not in phys screen */
 605:     /* Free any lines that used to be in phys screen but are no longer */
 606:     for (p = &PhysScreen[screen_height]; p != PhysScreen; p--)
 607:       if (p[0]) p[0]->physical = 1;
 608:     for (p = &DesiredScreen[screen_height]; p != DesiredScreen; p--)
 609:       {
 610:     if (l = *p)
 611:       {
 612:         if (!l->physical)
 613:           {
 614:         return_display_line (l);
 615:         /* Prevent line in both DesiredScreen and OPhysScreen
 616: 		   from being freed twice.  */
 617:         l->physical = 1;
 618:           }
 619:       }
 620:       }
 621:     for (p = &OPhysScreen[screen_height]; p != OPhysScreen; p--)
 622:       {
 623:     if (l = *p)
 624:       {
 625:         if (!l->physical)
 626:           return_display_line (l);
 627:       }
 628:       }
 629:     i = 0;
 630:     for (p = &PhysScreen[screen_height]; p != PhysScreen; p--)
 631:       if (p[0])
 632:     {
 633:       i++;
 634:       p[0]->physical = 0;
 635:     }
 636: 
 637:     {
 638:       extern int debug_end_pos;
 639:       if (debug_end_pos && i + free_line_count != 2 * screen_height)
 640:     abort ();
 641:     }
 642: 
 643:     bzero (OPhysScreen, (screen_height + 1) * sizeof OPhysScreen[0]);
 644:     bzero (DesiredScreen, (screen_height + 1) * sizeof DesiredScreen[0]);
 645:     return pause;
 646: }
 647: 
 648: /* Decide what insert/delete line to do, and do it */
 649: 
 650: scrolling ()
 651: {
 652:   int unchanged_at_top, unchanged_at_bottom;
 653:   int window_size;
 654:   int changed_lines;
 655:   int *old_hash = (int *) alloca (screen_height * sizeof (int));
 656:   int *new_hash = (int *) alloca (screen_height * sizeof (int));
 657:   int *draw_cost = (int *) alloca (screen_height * sizeof (int));
 658:   register int i;
 659:   int free_at_end_vpos = screen_height;
 660: 
 661:   /* Compute hash codes of all the lines.
 662:      Also calculate number of changed lines,
 663:      number of unchanged lines at the beginning,
 664:      and number of unchanged lines at the end.  */
 665: 
 666:   changed_lines = 0;
 667:   unchanged_at_top = 0;
 668:   unchanged_at_bottom = screen_height;
 669:   for (i = 0; i < screen_height; i++)
 670:     {
 671:       old_hash[i] = line_hash_code (PhysScreen[i + 1]);
 672:       if (!DesiredScreen[i + 1])
 673:     DesiredScreen[i + 1] = PhysScreen[i + 1];
 674:       if (PhysScreen[i + 1] == DesiredScreen[i + 1])
 675:     new_hash[i] = old_hash[i];
 676:       else
 677:     new_hash[i] = line_hash_code (DesiredScreen[i + 1]);
 678:       if (old_hash[i] != new_hash[i])
 679:     {
 680:       changed_lines++;
 681:       unchanged_at_bottom = screen_height - i - 1;
 682:     }
 683:       else if (i == unchanged_at_top)
 684:     unchanged_at_top++;
 685:       draw_cost[i] = line_draw_cost (DesiredScreen[i + 1]);
 686:     }
 687: 
 688:   /* If changed lines are few, don't allow preemption, don't scroll.  */
 689:   if (changed_lines < baud_rate / 2400 || unchanged_at_bottom == screen_height)
 690:     return 1;
 691: 
 692:   window_size = screen_height - unchanged_at_top - unchanged_at_bottom;
 693: 
 694:   if (scroll_region_ok)
 695:     free_at_end_vpos -= unchanged_at_bottom;
 696:   else if (memory_below_screen)
 697:     free_at_end_vpos = -1;
 698: 
 699:   /* If large window, fast terminal and few lines in common between
 700:      PhysScreen and DesiredScreen, don't bother with i/d calc.  */
 701:   if (window_size >= 18 && baud_rate > 2400
 702:       && (window_size >=
 703:       10 * scrolling_max_lines_saved (unchanged_at_top,
 704:                       screen_height - unchanged_at_bottom,
 705:                       old_hash, new_hash, draw_cost)))
 706:     return 0;
 707: 
 708:   scrolling_1 (window_size, unchanged_at_top, unchanged_at_bottom,
 709:            draw_cost + unchanged_at_top - 1,
 710:            old_hash + unchanged_at_top - 1,
 711:            new_hash + unchanged_at_top - 1,
 712:            free_at_end_vpos - unchanged_at_top);
 713: 
 714:   return 0;
 715: }
 716: 
 717: update_line (old, new, vpos)
 718:      struct display_line *old, *new;
 719:      int vpos;
 720: {
 721:   register char *obody, *nbody, *op1, *op2, *np1;
 722:   int tem;
 723:   int osp, nsp, m1, m2, olen, nlen;
 724:   int save;
 725: 
 726:   if (old == new)
 727:     return;
 728: 
 729:   /* Mark physical screen as containing the line `new' */
 730:   PhysScreen[vpos + 1] = new;
 731: 
 732:   if ((new && new->highlighted) != (old && old->highlighted))
 733:     {
 734:       change_line_highlight (new && new->highlighted, vpos, old ? old->length : 0);
 735:       old = 0;
 736:     }
 737:   else
 738:     reassert_line_highlight (new && new->highlighted, vpos);
 739: 
 740:   if (!old)
 741:     {
 742:       olen = 0;
 743:     }
 744:   else
 745:     {
 746:       obody = old -> body;
 747:       olen = old->length;
 748:       if (!must_write_spaces)
 749:     while (obody[olen - 1] == ' ')
 750:       olen--;
 751:     }
 752: 
 753:   if (!new)
 754:     {
 755:       nlen = 0;
 756:       goto just_erase;
 757:     }
 758: 
 759:   nbody = new -> body;
 760:   nlen = new->length;
 761: 
 762:   /* We know that the previous character is the `physical' field
 763:      and it is zero or one.  */
 764:   if (!must_write_spaces)
 765:     while (nbody[nlen - 1] == ' ')
 766:       nlen--;
 767: 
 768:   if (!olen)
 769:     {
 770:       nsp = (must_write_spaces || new->highlighted)
 771:           ? 0 : count_blanks (nbody);
 772:       if (nlen > nsp)
 773:     {
 774:       topos (vpos, nsp);
 775:       write_chars (nbody + nsp, nlen - nsp);
 776:     }
 777:       return;
 778:     }
 779: 
 780:   obody[olen] = 1;
 781:   save = nbody[nlen];
 782:   nbody[nlen] = 0;
 783: 
 784:   /* Compute number of leading blanks in old and new contents.  */
 785:   osp = count_blanks (obody);
 786:   if (!new->highlighted)
 787:     nsp = count_blanks (nbody);
 788:   else
 789:     nsp = 0;
 790: 
 791:   /* Compute number of matching chars starting with first nonblank.  */
 792:   m1 = count_match (obody + osp, nbody + nsp);
 793: 
 794:   /* Spaces in new match implicit space past the end of old.  */
 795:   /* This isn't really doing anything; osp should be osp + m1.
 796:      I don't dare fix it now since maybe if it does anything
 797:      it will do something bad.  */
 798:   if (!must_write_spaces && osp == olen)
 799:     {
 800:       np1 = nbody + nsp;
 801:       while (np1[m1] == ' ')
 802:     m1++;
 803:     }
 804: 
 805:   /* Avoid doing insert/delete char
 806:      just cause number of leading spaces differs
 807:      when the following text does not match. */
 808:   if (m1 == 0 && osp != nsp)
 809:     osp = nsp = min (osp, nsp);
 810: 
 811:   /* Find matching characters at end of line */
 812:   op1 = obody + olen;
 813:   np1 = nbody + nlen;
 814:   op2 = op1 + m1 - min (olen - osp, nlen - nsp);
 815:   while (op1 > op2 && op1[-1] == np1[-1])
 816:     {
 817:       op1--;
 818:       np1--;
 819:     }
 820:   m2 = obody + olen - op1;
 821: 
 822:   /* Put correct value back in nbody[nlen].
 823:      This is important because direct_output_for_insert
 824:      can write into the line at a later point.  */
 825:   nbody[nlen] = save;
 826: 
 827:   /* tem gets the distance to insert or delete.
 828:      m2 is how many characters we save by doing so.
 829:      Is it worth it?  */
 830: 
 831:   tem = (nlen - nsp) - (olen - osp);
 832:   if (m2 && tem && m2 <= DCICcost[tem])
 833:     m2 = 0;
 834: 
 835:   /* nsp - osp is the distance to insert or delete.
 836:      m1 + m2 is how much we save by doing so.
 837:      Is it worth it?  */
 838: 
 839:   if (m1 + m2 && nsp != osp && m1 + m2 <= DCICcost[nsp - osp])
 840:     {
 841:       m1 = 0;
 842:       m2 = 0;
 843:       osp = nsp = min (osp, nsp);
 844:     }
 845: 
 846:   /* Now go through the line, inserting, writing and deleting as appropriate.  */
 847: 
 848:   if (osp > nsp)
 849:     {
 850:       topos (vpos, nsp);
 851:       delete_chars (osp - nsp);
 852:     }
 853:   else if (nsp > osp)
 854:     {
 855:       /* If going to delete chars later in line
 856: 	 and insert earlier in the line,
 857: 	 must delete first to avoid losing data in the insert */
 858:       if (m2 && nlen < olen + nsp - osp)
 859:     {
 860:       topos (vpos, nlen - m2 + osp - nsp);
 861:       delete_chars (olen + nsp - osp - nlen);
 862:       olen = nlen - (nsp - osp);
 863:     }
 864:       topos (vpos, osp);
 865:       insert_chars ((char *)0, nsp - osp);
 866:     }
 867:   olen += nsp - osp;
 868:   osp = nsp;
 869: 
 870:   tem = nsp + m1 + m2;
 871:   if (nlen != tem || olen != tem)
 872:     {
 873:       topos (vpos, nsp + m1);
 874:       if (!m2 || nlen == olen)
 875:     {
 876:       /* If new text being written reaches right margin,
 877: 	     there is no need to do clear-to-eol at the end.
 878: 	     (and it would not be safe, since cursor is not
 879: 	     going to be "at the margin" after the text is done) */
 880:       if (nlen == screen_width)
 881:         olen = 0;
 882:       write_chars (nbody + nsp + m1, nlen - tem);
 883: #ifdef obsolete
 884: /* the following code loses disastrously if tem == nlen.
 885:    Rather than trying to fix that case, I am trying the simpler
 886:    solution found above.  */
 887:       /* If the text reaches to the right margin,
 888: 	     it will lose one way or another (depending on AutoWrap)
 889: 	     to clear to end of line after outputting all the text.
 890: 	     So pause with one character to go and clear the line then.  */
 891:       if (nlen == screen_width && fast_clear_end_of_line && olen > nlen)
 892:         {
 893:           /* m2 must be zero, and tem must equal nsp + m1 */
 894:           write_chars (nbody + tem, nlen - tem - 1);
 895:           clear_end_of_line (olen);
 896:           olen = 0;     /* Don't let it be cleared again later */
 897:           write_chars (nbody + nlen - 1, 1);
 898:         }
 899:       else
 900:         write_chars (nbody + nsp + m1, nlen - tem);
 901: #endif
 902:     }
 903:       else if (nlen > olen)
 904:     {
 905:       write_chars (nbody + nsp + m1, olen - tem);
 906:       insert_chars (nbody + nsp + m1 + olen - tem, nlen - olen);
 907:       olen = nlen;
 908:     }
 909:       else if (olen > nlen)
 910:     {
 911:       write_chars (nbody + nsp + m1, nlen - tem);
 912:       delete_chars (olen - nlen);
 913:       olen = nlen;
 914:     }
 915:     }
 916: 
 917:  just_erase:
 918:   /* If any unerased characters remain after the new line, erase them.  */
 919:   if (olen > nlen)
 920:     {
 921:       topos (vpos, nlen);
 922:       clear_end_of_line (olen);
 923:     }
 924: }
 925: 
 926: count_blanks (str)
 927:      char *str;
 928: {
 929:   register char *p = str;
 930:   while (*str++ == ' ');
 931:   return str - p - 1;
 932: }
 933: 
 934: count_match (str1, str2)
 935:      char *str1, *str2;
 936: {
 937:   register char *p1 = str1;
 938:   register char *p2 = str2;
 939:   while (*p1++ == *p2++);
 940:   return p1 - str1 - 1;
 941: }
 942: 
 943: DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript,
 944:   1, 1, "FOpen termscript file: ",
 945:   "Start writing all terminal output to FILE as well.")
 946:   (file)
 947:      Lisp_Object file;
 948: {
 949:   file = Fexpand_file_name (file, Qnil);
 950:   termscript = fopen (XSTRING (file)->data, "w");
 951:   return Qnil;
 952: }
 953: 
 954: DEFUN ("set-screen-height", Fset_screen_height, Sset_screen_height, 1, 1, 0,
 955:   "Set number of lines on screen available for use in windows.")
 956:   (n)
 957:      Lisp_Object n;
 958: {
 959:   CHECK_NUMBER (n, 0);
 960:   change_screen_size (XINT (n), 0);
 961:   return Qnil;
 962: }
 963: 
 964: DEFUN ("set-screen-width", Fset_screen_width, Sset_screen_width, 1, 1, 0,
 965:   "Set number of columns on screen available for display.")
 966:   (n)
 967:      Lisp_Object n;
 968: {
 969:   CHECK_NUMBER (n, 0);
 970:   change_screen_size (0, XINT (n));
 971:   return Qnil;
 972: }
 973: 
 974: DEFUN ("screen-height", Fscreen_height, Sscreen_height, 0, 0, 0,
 975:   "Return number of lines on screen available for use in windows.")
 976:   ()
 977: {
 978:   return make_number (screen_height);
 979: }
 980: 
 981: DEFUN ("screen-width", Fscreen_width, Sscreen_width, 0, 0, 0,
 982:   "Return number of columns on screen available for display.")
 983:   ()
 984: {
 985:   return make_number (screen_width);
 986: }
 987: 
 988: /* Change the screen height and/or width.  Values may be given as zero to
 989:    indicate no change is to take place. */
 990: change_screen_size (newlength, newwidth)
 991:      register int newlength, newwidth;
 992: {
 993:   if ((newlength == 0 || newlength == screen_height)
 994:       && (newwidth == 0 || newwidth == screen_width))
 995:       return;
 996:   if (newlength && newlength != screen_height)
 997:     {
 998:       if (newlength > MScreenLength)
 999:     newlength = MScreenLength;
1000:       set_window_height (XWINDOW (minibuf_window)->prev, newlength - 1, 0);
1001:       XFASTINT (XWINDOW (minibuf_window)->top) = newlength - 1;
1002:       set_window_height (minibuf_window, 1, 0);
1003:       screen_height = newlength;
1004:       set_terminal_window (0);
1005:     }
1006:   if (newwidth && newwidth != screen_width)
1007:     {
1008:       if (newwidth > MScreenWidth)
1009:     newwidth = MScreenWidth;
1010:       set_window_width (XWINDOW (minibuf_window)->prev, newwidth, 0);
1011:       set_window_width (minibuf_window, newwidth, 0);
1012:       screen_width = newwidth;
1013:     }
1014:   make_display_lines ();
1015:   calculate_costs ();
1016:   DoDsp (1);
1017: }
1018: 
1019: DEFSIMPLE ("baud-rate", Fbaud_rate, Sbaud_rate,
1020:        "Return the output baud rate of the terminal.",
1021:        Lisp_Int, XSETINT, baud_rate)
1022: 
1023: DEFUN ("send-string-to-terminal", Fsend_string_to_terminal,
1024:   Ssend_string_to_terminal, 1, 1, 0,
1025:   "Send STRING to the terminal without alteration.\n\
1026: Control characters in STRING will have terminal-dependent effects.")
1027:   (str)
1028:      Lisp_Object str;
1029: {
1030:   CHECK_STRING (str, 0);
1031:   fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, stdout);
1032:   fflush (stdout);
1033:   if (termscript)
1034:     {
1035:       fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, termscript);
1036:       fflush (termscript);
1037:     }
1038:   return Qnil;
1039: }
1040: 
1041: DEFUN ("ding", Fding, Sding, 0, 0, 0,
1042:   "Beep, or flash the screen.\n\
1043: Terminates any keyboard macro currently executing.")
1044:   ()
1045: {
1046:   Ding ();
1047:   return Qnil;
1048: }
1049: 
1050: Ding ()
1051: {
1052:   if (noninteractive)
1053:     putchar (07);
1054:   else if (!INTERACTIVE)  /* Stop executing a keyboard macro. */
1055:     error ("Keyboard macro terminated by a command ringing the bell");
1056:   else
1057:     ring_bell ();
1058:   fflush (stdout);
1059: }
1060: 
1061: DEFUN ("sleep-for", Fsleep_for, Ssleep_for, 1, 1, 0,
1062:   "Pause, without updating display, for ARG seconds.")
1063:   (n)
1064:      Lisp_Object n;
1065: {
1066:   register int t;
1067: #ifndef subprocesses
1068: #ifdef HAVE_TIMEVAL
1069:   struct timeval timeout, end_time, garbage1;
1070: #endif /* HAVE_TIMEVAL */
1071: #endif /* no subprocesses */
1072: 
1073:   CHECK_NUMBER (n, 0);
1074:   t = XINT (n);
1075:   if (t <= 0)
1076:     return Qnil;
1077: 
1078: #ifdef subprocesses
1079:   wait_reading_process_input (t, 0, 0);
1080: #else /* No subprocesses */
1081:   immediate_quit = 1;
1082:   QUIT;
1083: 
1084: #if defined(HAVE_SELECT) && defined(HAVE_TIMEVAL)
1085:   gettimeofday (&end_time, &garbage1);
1086:   end_time.tv_sec += t;
1087: 
1088:   while (1)
1089:     {
1090:       gettimeofday (&timeout, &garbage1);
1091:       timeout.tv_sec = end_time.tv_sec - timeout.tv_sec;
1092:       timeout.tv_usec = end_time.tv_usec - timeout.tv_usec;
1093:       if (timeout.tv_usec < 0)
1094:     timeout.tv_usec += 1000000,
1095:       timeout.tv_sec--;
1096:       if (timeout.tv_sec < 0)
1097:     break;
1098:       if (!select (1, 0, 0, 0, &timeout))
1099:     break;
1100:     }
1101: #else /* not both HAVE_SELECT and HAVE_TIMEVAL */
1102:   /* Is it safe to quit out of `sleep'?  I'm afraid to trust it.  */
1103:   sleep (t);
1104: #endif /* not both HAVE_SELECT and HAVE_TIMEVAL */
1105: 
1106:   immediate_quit = 0;
1107: #endif /* no subprocesses */
1108:   return Qnil;
1109: }
1110: 
1111: DEFUN ("sit-for", Fsit_for, Ssit_for, 1, 1, 0,
1112:   "Perform redisplay, then wait for ARG seconds or until input is available")
1113:   (n)
1114:      Lisp_Object n;
1115: {
1116: #ifndef subprocesses
1117: #ifdef HAVE_TIMEVAL
1118:   struct timeval timeout;
1119: #else
1120:   int timeout_sec;
1121: #endif
1122:   int waitchannels;
1123: #endif /* no subprocesses */
1124: 
1125:   CHECK_NUMBER (n, 0);
1126: 
1127:   if (detect_input_pending ())
1128:     return Qnil;
1129: 
1130:   DoDsp (1);            /* Make the screen correct */
1131:   if (XINT (n) <= 0) return Qnil;
1132: 
1133: #ifdef subprocesses
1134: #ifdef SIGIO
1135:   gobble_input ();
1136: #endif /* SIGIO */
1137:   wait_reading_process_input (XINT (n), 1, 1);
1138: #else /* no subprocesses */
1139:   immediate_quit = 1;
1140:   QUIT;
1141: 
1142:   waitchannels = 1;
1143: #ifndef HAVE_TIMEVAL
1144:   timeout_sec = XINT (n);
1145:   select (1, &waitchannels, 0, 0, &timeout_sec);
1146: #else /* HAVE_TIMEVAL */
1147:   timeout.tv_sec = XINT (n);
1148:   timeout.tv_usec = 0;
1149:   select (1, &waitchannels, 0, 0, &timeout);
1150: #endif /* HAVE_TIMEVAL */
1151: 
1152:   immediate_quit = 0;
1153: #endif /* no subprocesses */
1154:   return Qnil;
1155: }
1156: 
1157: char *terminal_type;
1158: 
1159: /* Initialization done when Emacs fork is started, before doing stty. */
1160: /* Determine terminal type and set terminal_driver */
1161: /* Then invoke its decoding routine to set up variables
1162:   in the terminal package */
1163: 
1164: init_display ()
1165: {
1166:   MetaFlag = 0;
1167:   inverse_video = 0;
1168: 
1169:   /* Look at the TERM variable and set terminal_driver.  */
1170: 
1171:   terminal_type = (char *) getenv ("TERM");
1172:   if (!terminal_type)
1173:     {
1174:       fprintf (stderr, "Please set the environment variable TERM; see tset(1).\n");
1175:       exit (1);
1176:     }
1177: #ifdef HAVE_X_WINDOWS
1178:   if (!strncmp (terminal_type, "xterm", 5))
1179:     x_term_init ();
1180:   else
1181: #endif /* HAVE_X_WINDOWS */
1182:     term_init (terminal_type);
1183: 
1184:   make_display_lines ();
1185: 
1186:   cursX = 0;        /* X and Y coordinates of the cursor */
1187:   cursY = 0;        /* between updates. */
1188: }
1189: 
1190: syms_of_display ()
1191: {
1192:   defsubr (&Sopen_termscript);
1193:   defsubr (&Sding);
1194:   defsubr (&Ssit_for);
1195:   defsubr (&Sscreen_height);
1196:   defsubr (&Sscreen_width);
1197:   defsubr (&Sset_screen_height);
1198:   defsubr (&Sset_screen_width);
1199:   defsubr (&Ssleep_for);
1200:   defsubr (&Sbaud_rate);
1201:   defsubr (&Ssend_string_to_terminal);
1202: 
1203:   DefBoolVar ("inverse-video", &inverse_video,
1204:     "*Non-nil means use inverse-video.");
1205:   DefBoolVar ("visible-bell", &visible_bell,
1206:     "*Non-nil means try to flash the screen to represent a bell.");
1207: }

Defined functions

DEFSIMPLE defined in line 1019; never used
DEFUN defined in line 1111; never used
cancel_line defined in line 258; used 2 times
cancel_my_columns defined in line 425; used 2 times
change_screen_size defined in line 990; used 4 times
clear_screen_records defined in line 187; used 1 times
count_blanks defined in line 926; used 4 times
count_match defined in line 934; used 1 times
direct_output_for_insert defined in line 441; used 1 times
init_display defined in line 1164; used 1 times
line_draw_cost defined in line 231; used 1 times
line_hash_code defined in line 197; used 2 times
make_display_lines defined in line 115; used 2 times
new_display_line defined in line 156; used 2 times
preserve_my_columns defined in line 391; never used
preserve_other_columns defined in line 351; used 2 times
return_display_line defined in line 175; used 6 times
scroll_screen_lines defined in line 302; used 2 times
scrolling defined in line 650; used 1 times
syms_of_display defined in line 1190; used 1 times
update_line defined in line 717; used 2 times

Defined variables

DesiredScreen defined in line 87; used 26 times
OPhysScreen defined in line 84; used 5 times
PhysScreen defined in line 81; used 35 times
Wcm defined in line 94; used 23 times
all_lines defined in line 90; used 1 times
baud_rate defined in line 76; used 8 times
cursY defined in line 63; used 48 times
display_completed defined in line 68; used 4 times
free_display_lines defined in line 105; used 8 times
free_line_count defined in line 109; used 5 times
inverse_video defined in line 73; used 4 times
terminal_type defined in line 1157; used 4 times
visible_bell defined in line 70; used 2 times

Defined macros

LINE_NEXT defined in line 100; used 3 times
SET_LINE_NEXT defined in line 101; used 3 times
max defined in line 52; used 3 times
min defined in line 53; used 5 times
Last modified: 1986-04-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2628
Valid CSS Valid XHTML 1.0 Strict