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: }