|
|
1.1 ! root 1: /* Newly written part of redisplay code. ! 2: Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU Emacs. ! 5: ! 6: GNU Emacs is free software; you can redistribute it and/or modify ! 7: it under the terms of the GNU General Public License as published by ! 8: the Free Software Foundation; either version 1, or (at your option) ! 9: any later version. ! 10: ! 11: GNU Emacs is distributed in the hope that it will be useful, ! 12: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 14: GNU General Public License for more details. ! 15: ! 16: You should have received a copy of the GNU General Public License ! 17: along with GNU Emacs; see the file COPYING. If not, write to ! 18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 19: ! 20: ! 21: /* This must precede sys/signal.h on certain machines. */ ! 22: #include <sys/types.h> ! 23: #include <signal.h> ! 24: ! 25: #include "config.h" ! 26: #include <stdio.h> ! 27: #include <errno.h> ! 28: ! 29: #ifdef HAVE_TIMEVAL ! 30: #ifdef HPUX ! 31: #include <time.h> ! 32: #else ! 33: #include <sys/time.h> ! 34: #endif ! 35: #endif ! 36: ! 37: #ifdef HAVE_TERMIO ! 38: #include <termio.h> ! 39: #ifdef TCOUTQ ! 40: #undef TIOCOUTQ ! 41: #define TIOCOUTQ TCOUTQ ! 42: #include <fcntl.h> ! 43: #endif /* TCOUTQ defined */ ! 44: #else ! 45: #ifndef VMS ! 46: #include <sys/ioctl.h> ! 47: #endif /* not VMS */ ! 48: #endif /* not HAVE_TERMIO */ ! 49: ! 50: /* Allow m- file to inhibit use of FIONREAD. */ ! 51: #ifdef BROKEN_FIONREAD ! 52: #undef FIONREAD ! 53: #endif ! 54: ! 55: /* We are unable to use interrupts if FIONREAD is not available, ! 56: so flush SIGIO so we won't try. */ ! 57: #ifndef FIONREAD ! 58: #ifdef SIGIO ! 59: #undef SIGIO ! 60: #endif ! 61: #endif ! 62: ! 63: #undef NULL ! 64: ! 65: #include "termchar.h" ! 66: #include "termopts.h" ! 67: #include "cm.h" ! 68: #include "dispextern.h" ! 69: #include "lisp.h" ! 70: #include "buffer.h" ! 71: #include "window.h" ! 72: #include "commands.h" ! 73: ! 74: #define max(a, b) ((a) > (b) ? (a) : (b)) ! 75: #define min(a, b) ((a) < (b) ? (a) : (b)) ! 76: ! 77: #ifndef PENDING_OUTPUT_COUNT ! 78: /* Get number of chars of output now in the buffer of a stdio stream. ! 79: This ought to be built in in stdio, but it isn't. ! 80: Some s- files override this because their stdio internals differ. */ ! 81: #ifdef __GNU_LIBRARY__ ! 82: #define PENDING_OUTPUT_COUNT(FILE) ((FILE)->__bufp - (FILE)->__buffer) ! 83: #else ! 84: #define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_ptr - (FILE)->_base) ! 85: #endif ! 86: #endif /* No PENDING_OUTPUT_COUNT */ ! 87: ! 88: /* Nonzero means do not assume anything about current ! 89: contents of actual terminal screen */ ! 90: ! 91: int screen_garbaged; ! 92: ! 93: /* Desired terminal cursor position (to show position of point), ! 94: origin zero */ ! 95: ! 96: int cursor_hpos, cursor_vpos; ! 97: ! 98: /* Nonzero means last display completed and cursor is really at ! 99: cursor_hpos, cursor_vpos. Zero means it was preempted. */ ! 100: ! 101: int display_completed; ! 102: ! 103: /* Lisp variable visible-bell; enables use of screen-flash ! 104: instead of audible bell. */ ! 105: ! 106: int visible_bell; ! 107: ! 108: /* Invert the color of the whole screen, at a low level. */ ! 109: ! 110: int inverse_video; ! 111: ! 112: /* Line speed of the terminal. */ ! 113: ! 114: int baud_rate; ! 115: ! 116: /* nil or a symbol naming the window system ! 117: under which emacs is running ! 118: ('x is the only current possibility). */ ! 119: ! 120: Lisp_Object Vwindow_system; ! 121: ! 122: /* Version number of window system, or nil if no window system. */ ! 123: ! 124: Lisp_Object Vwindow_system_version; ! 125: ! 126: /* Nonzero means reading single-character input with prompt ! 127: so put cursor on minibuffer after the prompt. */ ! 128: ! 129: int cursor_in_echo_area; ! 130: ! 131: /* Nonzero means finish redisplay regardless of available input. ! 132: This is used with X windows to avoid a weird timing-dependent bug. */ ! 133: ! 134: int force_redisplay; ! 135: ! 136: /* Description of actual screen contents. */ ! 137: ! 138: struct matrix *current_screen; ! 139: ! 140: /* Description of desired screen contents. */ ! 141: ! 142: struct matrix *new_screen; ! 143: ! 144: /* Buffer sometimes used to hold partial screen contents. */ ! 145: ! 146: struct matrix *temp_screen; ! 147: ! 148: /* Stdio stream being used for copy of all terminal output. */ ! 149: ! 150: FILE *termscript; ! 151: ! 152: /* Structure for info on cursor positioning */ ! 153: ! 154: struct cm Wcm; ! 155: ! 156: int delayed_size_change; /* 1 means SIGWINCH happened when not safe. */ ! 157: int delayed_screen_height; /* Remembered new screen height. */ ! 158: int delayed_screen_width; /* Remembered new screen width. */ ! 159: ! 160: /* This buffer records the history of display preemption. */ ! 161: ! 162: struct preempt ! 163: { ! 164: /* Number of keyboard characters read so far at preempt. */ ! 165: int keyboard_char_count; ! 166: /* Vertical position at which preemption occurred. */ ! 167: int vpos; ! 168: }; ! 169: ! 170: #define N_PREEMPTIONS 50 ! 171: ! 172: /* Circular buffer recording recent display preemptions. */ ! 173: struct preempt preemptions[N_PREEMPTIONS]; ! 174: ! 175: /* Index of next element in preemptions. */ ! 176: int preemption_index; ! 177: ! 178: /* Set these variables in the debugger to force a display preemption. */ ! 179: int debug_preemption_vpos = -1; ! 180: int debug_preemption_char_count = -1; ! 181: ! 182: extern int num_input_chars; ! 183: ! 184: /* Free and reallocate current_screen and new_screen. */ ! 185: ! 186: struct matrix *make_screen_structure (); ! 187: ! 188: remake_screen_structures () ! 189: { ! 190: int i; ! 191: ! 192: if (current_screen) ! 193: free_screen_structure (current_screen); ! 194: if (new_screen) ! 195: free_screen_structure (new_screen); ! 196: if (temp_screen) ! 197: free_screen_structure (temp_screen); ! 198: ! 199: current_screen = make_screen_structure (0); ! 200: new_screen = make_screen_structure (0); ! 201: temp_screen = make_screen_structure (1); ! 202: ! 203: if (message_buf) ! 204: { ! 205: /* The echo_area_contents, used by error and message, may be pointing at ! 206: the string we are replacing. If so, update it. */ ! 207: int repair_echo_area_contents = echo_area_contents == message_buf; ! 208: ! 209: message_buf = (char *) xrealloc (message_buf, screen_width + 1); ! 210: ! 211: if (repair_echo_area_contents) echo_area_contents = message_buf; ! 212: } ! 213: else ! 214: message_buf = (char *) xmalloc (screen_width + 1); ! 215: ! 216: /* This may fix a problem of occasionally displaying garbage in the echo area ! 217: after a resize in X Windows. */ ! 218: for (i = 0; i < screen_width; i++) ! 219: message_buf[i] = ' '; ! 220: message_buf[screen_width] = 0; ! 221: } ! 222: ! 223: struct matrix * ! 224: make_screen_structure (empty) ! 225: int empty; ! 226: { ! 227: int i; ! 228: struct matrix *new = (struct matrix *) xmalloc (sizeof (struct matrix)); ! 229: ! 230: new->height = screen_height; ! 231: new->width = screen_width; ! 232: new->highlight = (char *) xmalloc (screen_height); ! 233: new->enable = (char *) xmalloc (screen_height); ! 234: new->contents = (unsigned char **) xmalloc (screen_height * sizeof (char *)); ! 235: new->used = (int *) xmalloc (screen_height * sizeof (int)); ! 236: if (empty) ! 237: { ! 238: /* Make the buffer used by decode_mode_spec. */ ! 239: new->total_contents = (unsigned char *) xmalloc (screen_width + 2); ! 240: for (i = 0; i < screen_width; i++) ! 241: new->total_contents[i] = ' '; ! 242: new->total_contents[screen_width] = 0; ! 243: } ! 244: else ! 245: { ! 246: /* Add 2 to leave extra bytes at beginning and end of each line. */ ! 247: new->total_contents = (unsigned char *) xmalloc (screen_height * (screen_width + 2)); ! 248: for (i = 0; i < screen_height; i++) ! 249: { ! 250: int j; ! 251: ! 252: new->contents[i] = new->total_contents + i * (screen_width + 2) + 1; ! 253: new->contents[i][screen_width] = 0; ! 254: new->contents[i][-1] = 0; ! 255: for (j = 0; j < screen_width; j++) ! 256: new->contents[i][j] = ' '; ! 257: } ! 258: } ! 259: bzero (new->enable, screen_height); ! 260: return new; ! 261: } ! 262: ! 263: free_screen_structure (matrix) ! 264: struct matrix *matrix; ! 265: { ! 266: if (matrix->total_contents) ! 267: free (matrix->total_contents); ! 268: free (matrix->contents); ! 269: free (matrix->highlight); ! 270: free (matrix->enable); ! 271: free (matrix->used); ! 272: free (matrix); ! 273: } ! 274: ! 275: /* Return the hash code of contents of line VPOS of screen-matrix M. */ ! 276: ! 277: int ! 278: line_hash_code (m, vpos) ! 279: struct matrix *m; ! 280: int vpos; ! 281: { ! 282: register unsigned char *body; ! 283: register int h = 0; ! 284: /* Give all lighlighted lines the same hash code ! 285: so as to encourage scrolling to leave them in place. */ ! 286: if (m->highlight[vpos]) ! 287: return -1; ! 288: ! 289: body = m->contents[vpos]; ! 290: ! 291: if (must_write_spaces) ! 292: { ! 293: while (1) ! 294: { ! 295: int c = *body++; ! 296: if (c == 0) ! 297: break; ! 298: h = (((h << 4) + (h >> 24)) & 0x0fffffff) + c - ' '; ! 299: } ! 300: } ! 301: else ! 302: { ! 303: while (1) ! 304: { ! 305: int c = *body++; ! 306: if (c == 0) ! 307: break; ! 308: h = (((h << 4) + (h >> 24)) & 0x0fffffff) + c; ! 309: } ! 310: } ! 311: if (h) ! 312: return h; ! 313: return 1; ! 314: } ! 315: ! 316: /* Return number of characters in line in M at vpos VPOS, ! 317: except don't count leading and trailing spaces ! 318: unless the terminal requires those to be explicitly output. */ ! 319: ! 320: int ! 321: line_draw_cost (m, vpos) ! 322: struct matrix *m; ! 323: int vpos; ! 324: { ! 325: register unsigned char *body; ! 326: register int i; ! 327: ! 328: if (must_write_spaces) ! 329: return m->used[vpos]; ! 330: ! 331: body = m->contents[vpos]; ! 332: for (i = m->used[vpos]; i > 0 && body[i - 2] == ' '; i--); ! 333: ! 334: i -= count_blanks (body); ! 335: return max (i, 0); ! 336: } ! 337: ! 338: /* The functions on this page are the interface from xdisp.c to redisplay. ! 339: ! 340: The only other interface into redisplay is through setting ! 341: cursor_hpos and cursor_vpos (in xdisp.c) and setting screen_garbaged. */ ! 342: ! 343: /* cancel_line eliminates any request to display a line at position `vpos' */ ! 344: ! 345: cancel_line (vpos) ! 346: int vpos; ! 347: { ! 348: new_screen->enable[vpos] = 0; ! 349: } ! 350: ! 351: clear_screen_records () ! 352: { ! 353: int i; ! 354: ! 355: bzero (current_screen->enable, screen_height); ! 356: } ! 357: ! 358: /* Get ready to display on line `vpos' ! 359: and set it up for outputting starting at `hpos' within it. ! 360: Return the text string where that line is stored. */ ! 361: ! 362: unsigned char * ! 363: get_display_line (vpos, hpos) ! 364: int vpos; ! 365: register int hpos; ! 366: { ! 367: if (new_screen->enable[vpos] && new_screen->used[vpos] > hpos) ! 368: abort (); ! 369: if (! new_screen->enable[vpos]) ! 370: { ! 371: new_screen->used[vpos] = 0; ! 372: new_screen->highlight[vpos] = 0; ! 373: new_screen->enable[vpos] = 1; ! 374: } ! 375: ! 376: if (hpos > new_screen->used[vpos]) ! 377: { ! 378: unsigned char *p = new_screen->contents[vpos] + new_screen->used[vpos]; ! 379: unsigned char *end = new_screen->contents[vpos] + hpos; ! 380: new_screen->used[vpos] = hpos; ! 381: while (p != end) ! 382: *p++ = ' '; ! 383: } ! 384: ! 385: return new_screen->contents[vpos]; ! 386: } ! 387: ! 388: /* Scroll lines from vpos `from' up to but not including vpos `end' ! 389: down by `amount' lines (`amount' may be negative). ! 390: Returns nonzero if done, zero if terminal cannot scroll them. */ ! 391: ! 392: int ! 393: scroll_screen_lines (from, end, amount) ! 394: int from, end, amount; ! 395: { ! 396: register int i; ! 397: ! 398: if (!line_ins_del_ok) ! 399: return 0; ! 400: ! 401: if (amount == 0) ! 402: return 1; ! 403: if (amount > 0) ! 404: { ! 405: set_terminal_window (end + amount); ! 406: if (!scroll_region_ok) ! 407: ins_del_lines (end, -amount); ! 408: ins_del_lines (from, amount); ! 409: set_terminal_window (0); ! 410: ! 411: rotate_vector (current_screen->contents + from, ! 412: sizeof (char *) * (end + amount - from), ! 413: amount * sizeof (char *)); ! 414: safe_bcopy (current_screen->used + from, ! 415: current_screen->used + from + amount, ! 416: (end - from) * sizeof current_screen->used[0]); ! 417: safe_bcopy (current_screen->highlight + from, ! 418: current_screen->highlight + from + amount, ! 419: (end - from) * sizeof current_screen->highlight[0]); ! 420: safe_bcopy (current_screen->enable + from, ! 421: current_screen->enable + from + amount, ! 422: (end - from) * sizeof current_screen->enable[0]); ! 423: /* Mark the lines made empty by scrolling as enabled, empty and ! 424: normal video. */ ! 425: bzero (current_screen->used + from, ! 426: amount * sizeof current_screen->used[0]); ! 427: bzero (current_screen->highlight + from, ! 428: amount * sizeof current_screen->highlight[0]); ! 429: for (i = from; i < from + amount; i++) ! 430: { ! 431: current_screen->contents[i][0] = '\0'; ! 432: current_screen->enable[i] = 1; ! 433: } ! 434: } ! 435: if (amount < 0) ! 436: { ! 437: set_terminal_window (end); ! 438: ins_del_lines (from + amount, amount); ! 439: if (!scroll_region_ok) ! 440: ins_del_lines (end + amount, -amount); ! 441: set_terminal_window (0); ! 442: ! 443: rotate_vector (current_screen->contents + from + amount, ! 444: sizeof (char *) * (end - from - amount), ! 445: (end - from) * sizeof (char *)); ! 446: safe_bcopy (current_screen->used + from, ! 447: current_screen->used + from + amount, ! 448: (end - from) * sizeof current_screen->used[0]); ! 449: safe_bcopy (current_screen->highlight + from, ! 450: current_screen->highlight + from + amount, ! 451: (end - from) * sizeof current_screen->highlight[0]); ! 452: safe_bcopy (current_screen->enable + from, ! 453: current_screen->enable + from + amount, ! 454: (end - from) * sizeof current_screen->enable[0]); ! 455: /* Mark the lines made empty by scrolling as enabled, empty and ! 456: normal video. */ ! 457: bzero (current_screen->used + end + amount, ! 458: - amount * sizeof current_screen->used[0]); ! 459: bzero (current_screen->highlight + end + amount, ! 460: - amount * sizeof current_screen->highlight[0]); ! 461: for (i = end + amount; i < end; i++) ! 462: { ! 463: current_screen->contents[i][0] = '\0'; ! 464: current_screen->enable[i] = 1; ! 465: } ! 466: } ! 467: return 1; ! 468: } ! 469: ! 470: /* Rotate a vector of SIZE bytes, by DISTANCE bytes. ! 471: DISTANCE may be negative. */ ! 472: ! 473: rotate_vector (vector, size, distance) ! 474: char *vector; ! 475: int size; ! 476: int distance; ! 477: { ! 478: char *temp = (char *) alloca (size); ! 479: ! 480: if (distance < 0) ! 481: distance += size; ! 482: ! 483: bcopy (vector, temp + distance, size - distance); ! 484: bcopy (vector + size - distance, temp, distance); ! 485: bcopy (temp, vector, size); ! 486: } ! 487: ! 488: /* Like bcopy except never gets confused by overlap. */ ! 489: ! 490: safe_bcopy (from, to, size) ! 491: char *from, *to; ! 492: int size; ! 493: { ! 494: register char *endf; ! 495: register char *endt; ! 496: ! 497: if (size == 0) ! 498: return; ! 499: if (from > to) ! 500: { ! 501: /* If destination is lower in memory, we can go from the beginning. */ ! 502: endf = from + size; ! 503: while (from != endf) ! 504: *to++ = *from++; ! 505: return; ! 506: } ! 507: ! 508: /* If destination is higher in memory, we can go backwards from the end. */ ! 509: endf = from + size; ! 510: endt = to + size; ! 511: ! 512: do ! 513: *--endt = *--endf; ! 514: while (endf != from); ! 515: } ! 516: ! 517: /* After updating a window w that isn't the full screen wide, ! 518: copy all the columns that w does not occupy ! 519: from current_screen to new_screen, ! 520: so that update_screen will not change those columns. */ ! 521: ! 522: preserve_other_columns (w) ! 523: struct window *w; ! 524: { ! 525: register int vpos; ! 526: int start = XFASTINT (w->left); ! 527: int end = XFASTINT (w->left) + XFASTINT (w->width); ! 528: int bot = XFASTINT (w->top) + XFASTINT (w->height); ! 529: ! 530: for (vpos = XFASTINT (w->top); vpos < bot; vpos++) ! 531: { ! 532: if (current_screen->enable[vpos] && new_screen->enable[vpos]) ! 533: { ! 534: if (start > 0) ! 535: { ! 536: int len; ! 537: ! 538: bcopy (current_screen->contents[vpos], ! 539: new_screen->contents[vpos], start); ! 540: len = min (start, current_screen->used[vpos]); ! 541: if (new_screen->used[vpos] < len) ! 542: new_screen->used[vpos] = len; ! 543: } ! 544: if (current_screen->used[vpos] > end ! 545: && new_screen->used[vpos] < current_screen->used[vpos]) ! 546: { ! 547: while (new_screen->used[vpos] < end) ! 548: new_screen->contents[vpos][new_screen->used[vpos]++] = ' '; ! 549: bcopy (current_screen->contents[vpos] + end, ! 550: new_screen->contents[vpos] + end, ! 551: current_screen->used[vpos] - end); ! 552: new_screen->used[vpos] = current_screen->used[vpos]; ! 553: } ! 554: } ! 555: } ! 556: } ! 557: ! 558: /* On discovering that the redisplay for a window was no good, ! 559: cancel the columns of that window, ! 560: so that when the window is displayed over again ! 561: get_display_line will not complain. */ ! 562: ! 563: cancel_my_columns (w) ! 564: struct window *w; ! 565: { ! 566: register int vpos; ! 567: register int start = XFASTINT (w->left); ! 568: register int bot = XFASTINT (w->top) + XFASTINT (w->height); ! 569: ! 570: for (vpos = XFASTINT (w->top); vpos < bot; vpos++) ! 571: if (new_screen->enable[vpos] && new_screen->used[vpos] >= start) ! 572: new_screen->used[vpos] = start; ! 573: } ! 574: ! 575: /* These functions try to perform directly and immediately on the screen ! 576: the necessary output for one change in the buffer. ! 577: They may return 0 meaning nothing was done if anything is difficult, ! 578: or 1 meaning the output was performed properly. ! 579: They assume that the screen was up to date before the buffer ! 580: change being displayed. THey make various other assumptions too; ! 581: see command_loop_1 where these are called. */ ! 582: ! 583: int ! 584: direct_output_for_insert (c) ! 585: int c; ! 586: { ! 587: #ifndef COMPILER_REGISTER_BUG ! 588: register ! 589: #endif COMPILER_REGISTER_BUG ! 590: struct window *w = XWINDOW (selected_window); ! 591: #ifndef COMPILER_REGISTER_BUG ! 592: register ! 593: #endif COMPILER_REGISTER_BUG ! 594: int hpos = cursor_hpos; ! 595: #ifndef COMPILER_REGISTER_BUG ! 596: register ! 597: #endif COMPILER_REGISTER_BUG ! 598: int vpos = cursor_vpos; ! 599: ! 600: /* Give up if about to continue line */ ! 601: if (hpos - XFASTINT (w->left) + 1 + 1 >= XFASTINT (w->width) ! 602: ! 603: /* Avoid losing if cursor is in invisible text off left margin */ ! 604: || (XINT (w->hscroll) && hpos == XFASTINT (w->left)) ! 605: ! 606: /* Give up if cursor outside window (in minibuf, probably) */ ! 607: || cursor_vpos < XFASTINT (w->top) ! 608: || cursor_vpos >= XFASTINT (w->top) + XFASTINT (w->height) ! 609: ! 610: /* Give up if cursor not really at cursor_hpos, cursor_vpos */ ! 611: || !display_completed ! 612: ! 613: /* Give up if w is minibuffer and a message is being displayed there */ ! 614: || (EQ (selected_window, minibuf_window) && echo_area_contents)) ! 615: return 0; ! 616: ! 617: current_screen->contents[vpos][hpos] = c; ! 618: unchanged_modified = MODIFF; ! 619: beg_unchanged = GPT - BEG; ! 620: XFASTINT (w->last_point) = point; ! 621: XFASTINT (w->last_point_x) = cursor_hpos; ! 622: XFASTINT (w->last_modified) = MODIFF; ! 623: ! 624: reassert_line_highlight (0, cursor_vpos); ! 625: output_chars (¤t_screen->contents[vpos][hpos], 1); ! 626: fflush (stdout); ! 627: ++cursor_hpos; ! 628: if (hpos == current_screen->used[vpos]) ! 629: { ! 630: current_screen->used[vpos] = hpos + 1; ! 631: current_screen->contents[vpos][hpos + 1] = 0; ! 632: } ! 633: return 1; ! 634: } ! 635: ! 636: int ! 637: direct_output_forward_char (n) ! 638: int n; ! 639: { ! 640: register struct window *w = XWINDOW (selected_window); ! 641: ! 642: /* Avoid losing if cursor is in invisible text off left margin */ ! 643: if (XINT (w->hscroll) && cursor_hpos == XFASTINT (w->left)) ! 644: return 0; ! 645: /* Don't lose if we are in the truncated text at the end. */ ! 646: if (cursor_hpos >= XFASTINT (w->left) + XFASTINT (w->width) - 1) ! 647: return 0; ! 648: /* Don't move past the window edges. */ ! 649: if (cursor_hpos + n >= XFASTINT (w->left) + XFASTINT (w->width) - 1) ! 650: return 0; ! 651: if (cursor_hpos + n <= XFASTINT (w->left)) ! 652: return 0; ! 653: ! 654: cursor_hpos += n; ! 655: XFASTINT (w->last_point_x) = cursor_hpos; ! 656: XFASTINT (w->last_point) = point; ! 657: move_cursor (cursor_vpos, cursor_hpos); ! 658: fflush (stdout); ! 659: return 1; ! 660: } ! 661: ! 662: /* Update the actual terminal screen based on the data in new_screen. ! 663: Value is nonzero if redisplay stopped due to pending input. ! 664: FORCE nonzero means do not stop for pending input. */ ! 665: ! 666: update_screen (force, inhibit_hairy_id) ! 667: int force; ! 668: int inhibit_hairy_id; ! 669: { ! 670: register struct display_line **p; ! 671: register struct display_line *l, *lnew; ! 672: register int i; ! 673: int pause; ! 674: int preempt_count = baud_rate / 2400 + 1; ! 675: extern input_pending; ! 676: ! 677: if (screen_height == 0) abort (); /* Some bug zeros some core */ ! 678: ! 679: if (force_redisplay) ! 680: force = 1; ! 681: ! 682: if (!force) ! 683: detect_input_pending (); ! 684: if (!force ! 685: && ((num_input_chars == debug_preemption_char_count ! 686: && debug_preemption_vpos == screen_height - 1) ! 687: || input_pending)) ! 688: { ! 689: pause = screen_height; ! 690: goto do_pause; ! 691: } ! 692: ! 693: update_begin (); ! 694: ! 695: if (!line_ins_del_ok) ! 696: inhibit_hairy_id = 1; ! 697: ! 698: /* Don't compute for i/d line if just want cursor motion. */ ! 699: for (i = 0; i < screen_height; i++) ! 700: if (new_screen->enable) ! 701: break; ! 702: ! 703: /* Try doing i/d line, if not yet inhibited. */ ! 704: if (!inhibit_hairy_id && i < screen_height) ! 705: force |= scrolling (); ! 706: ! 707: /* Update the individual lines as needed. Do bottom line first. */ ! 708: ! 709: if (new_screen->enable[screen_height - 1]) ! 710: update_line (screen_height - 1); ! 711: for (i = 0; i < screen_height - 1 && (force || !input_pending); i++) ! 712: { ! 713: if (!force && num_input_chars == debug_preemption_char_count ! 714: && debug_preemption_vpos == i) ! 715: break; ! 716: if (new_screen->enable[i]) ! 717: { ! 718: /* Flush out every so many lines. ! 719: Also flush out if likely to have more than 1k buffered ! 720: otherwise. I'm told that telnet connections get really ! 721: screwed by more than 1k output at once. */ ! 722: int outq = PENDING_OUTPUT_COUNT (stdout); ! 723: if (outq > 900 ! 724: || (outq > 20 && ((i - 1) % preempt_count == 0))) ! 725: { ! 726: fflush (stdout); ! 727: if (preempt_count == 1) ! 728: { ! 729: #ifdef TIOCOUTQ ! 730: if (ioctl (0, TIOCOUTQ, &outq) < 0) ! 731: /* Probably not a tty. Ignore the error and reset ! 732: * the outq count. */ ! 733: outq = PENDING_OUTPUT_COUNT (stdout); ! 734: #endif ! 735: outq *= 10; ! 736: sleep (outq / baud_rate); ! 737: } ! 738: } ! 739: if ((i - 1) % preempt_count == 0 && !force) ! 740: detect_input_pending (); ! 741: /* Now update this line. */ ! 742: update_line (i); ! 743: } ! 744: } ! 745: pause = (i < screen_height - 1) ? i + 1 : 0; ! 746: ! 747: /* Now just clean up termcap drivers and set cursor, etc. */ ! 748: if (!pause) ! 749: { ! 750: if (cursor_in_echo_area < 0) ! 751: move_cursor (screen_height - 1, 0); ! 752: else if (cursor_in_echo_area > 0 ! 753: && !current_screen->enable[screen_height - 1]) ! 754: move_cursor (screen_height - 1, 0); ! 755: else if (cursor_in_echo_area) ! 756: move_cursor (screen_height - 1, ! 757: min (screen_width - 1, ! 758: current_screen->used[screen_height - 1])); ! 759: else ! 760: move_cursor (cursor_vpos, max (min (cursor_hpos, screen_width - 1), 0)); ! 761: } ! 762: ! 763: update_end (); ! 764: ! 765: if (termscript) ! 766: fflush (termscript); ! 767: fflush (stdout); ! 768: ! 769: /* Here if output is preempted because input is detected. */ ! 770: do_pause: ! 771: ! 772: if (screen_height == 0) abort (); /* Some bug zeros some core */ ! 773: display_completed = !pause; ! 774: if (pause) ! 775: { ! 776: preemptions[preemption_index].vpos = pause - 1; ! 777: preemptions[preemption_index].keyboard_char_count = num_input_chars; ! 778: preemption_index++; ! 779: if (preemption_index == N_PREEMPTIONS) ! 780: preemption_index = 0; ! 781: } ! 782: ! 783: bzero (new_screen->enable, screen_height); ! 784: return pause; ! 785: } ! 786: ! 787: /* Called when about to quit, to check for doing so ! 788: at an improper time. */ ! 789: ! 790: void ! 791: quit_error_check () ! 792: { ! 793: if (new_screen == 0) ! 794: return; ! 795: if (new_screen->enable[0]) ! 796: abort (); ! 797: if (new_screen->enable[screen_height - 1]) ! 798: abort (); ! 799: } ! 800: ! 801: /* Decide what insert/delete line to do, and do it */ ! 802: ! 803: scrolling () ! 804: { ! 805: int unchanged_at_top, unchanged_at_bottom; ! 806: int window_size; ! 807: int changed_lines; ! 808: int *old_hash = (int *) alloca (screen_height * sizeof (int)); ! 809: int *new_hash = (int *) alloca (screen_height * sizeof (int)); ! 810: int *draw_cost = (int *) alloca (screen_height * sizeof (int)); ! 811: register int i; ! 812: int free_at_end_vpos = screen_height; ! 813: ! 814: /* Compute hash codes of all the lines. ! 815: Also calculate number of changed lines, ! 816: number of unchanged lines at the beginning, ! 817: and number of unchanged lines at the end. */ ! 818: ! 819: changed_lines = 0; ! 820: unchanged_at_top = 0; ! 821: unchanged_at_bottom = screen_height; ! 822: for (i = 0; i < screen_height; i++) ! 823: { ! 824: /* Give up on this scrolling if some old lines are not enabled. */ ! 825: if (!current_screen->enable[i]) ! 826: return 0; ! 827: old_hash[i] = line_hash_code (current_screen, i); ! 828: if (!new_screen->enable[i]) ! 829: new_hash[i] = old_hash[i]; ! 830: else ! 831: new_hash[i] = line_hash_code (new_screen, i); ! 832: if (old_hash[i] != new_hash[i]) ! 833: { ! 834: changed_lines++; ! 835: unchanged_at_bottom = screen_height - i - 1; ! 836: } ! 837: else if (i == unchanged_at_top) ! 838: unchanged_at_top++; ! 839: /* If line is not changing, its redraw cost is infinite, ! 840: since we can't redraw it. */ ! 841: if (!new_screen->enable[i]) ! 842: draw_cost[i] = INFINITY; ! 843: else ! 844: draw_cost[i] = line_draw_cost (new_screen, i); ! 845: } ! 846: ! 847: /* If changed lines are few, don't allow preemption, don't scroll. */ ! 848: if (changed_lines < baud_rate / 2400 || unchanged_at_bottom == screen_height) ! 849: return 1; ! 850: ! 851: window_size = screen_height - unchanged_at_top - unchanged_at_bottom; ! 852: ! 853: if (scroll_region_ok) ! 854: free_at_end_vpos -= unchanged_at_bottom; ! 855: else if (memory_below_screen) ! 856: free_at_end_vpos = -1; ! 857: ! 858: /* If large window, fast terminal and few lines in common between ! 859: current_screen and new_screen, don't bother with i/d calc. */ ! 860: if (window_size >= 18 && baud_rate > 2400 ! 861: && (window_size >= ! 862: 10 * scrolling_max_lines_saved (unchanged_at_top, ! 863: screen_height - unchanged_at_bottom, ! 864: old_hash, new_hash, draw_cost))) ! 865: return 0; ! 866: ! 867: scrolling_1 (window_size, unchanged_at_top, unchanged_at_bottom, ! 868: draw_cost + unchanged_at_top - 1, ! 869: old_hash + unchanged_at_top - 1, ! 870: new_hash + unchanged_at_top - 1, ! 871: free_at_end_vpos - unchanged_at_top); ! 872: ! 873: return 0; ! 874: } ! 875: ! 876: update_line (vpos) ! 877: int vpos; ! 878: { ! 879: register unsigned char *obody, *nbody, *op1, *op2, *np1; ! 880: int tem; ! 881: int osp, nsp, begmatch, endmatch, olen, nlen; ! 882: int save; ! 883: unsigned char *temp; ! 884: ! 885: /* Check for highlighting change. */ ! 886: if (new_screen->highlight[vpos] ! 887: != (current_screen->enable[vpos] && current_screen->highlight[vpos])) ! 888: { ! 889: change_line_highlight (new_screen->highlight[vpos], vpos, ! 890: (current_screen->enable[vpos] ! 891: ? current_screen->used[vpos] : 0)); ! 892: current_screen->enable[vpos] = 0; ! 893: } ! 894: else ! 895: reassert_line_highlight (new_screen->highlight[vpos], vpos); ! 896: ! 897: /* ??? */ ! 898: if (! current_screen->enable[vpos]) ! 899: { ! 900: olen = 0; ! 901: } ! 902: else ! 903: { ! 904: obody = current_screen->contents[vpos]; ! 905: olen = current_screen->used[vpos]; ! 906: ! 907: /* Check for bugs that clobber obody[-1]. ! 908: Such bugs might well clobber more than that, ! 909: so we need to find them, not try to ignore them. */ ! 910: if (obody[-1] != 0) ! 911: abort (); ! 912: ! 913: if (! current_screen->highlight[vpos]) ! 914: { ! 915: /* Note obody[-1] is always 0. */ ! 916: if (!must_write_spaces) ! 917: while (obody[olen - 1] == ' ') ! 918: olen--; ! 919: } ! 920: else ! 921: { ! 922: /* For an inverse-video line, remember we gave it ! 923: spaces all the way to the screen edge ! 924: so that the reverse video extends all the way across. */ ! 925: while (olen < screen_width - 1) ! 926: obody[olen++] = ' '; ! 927: } ! 928: } ! 929: ! 930: /* One way or another, this will enable the line being updated. */ ! 931: current_screen->enable[vpos] = 1; ! 932: current_screen->used[vpos] = new_screen->used[vpos]; ! 933: #if !defined (ALLIANT) || defined (ALLIANT_2800) ! 934: current_screen->highlight[vpos] = new_screen->highlight[vpos]; ! 935: #else ! 936: { ! 937: /* Work around for compiler bug in cc on FX/80 which causes ! 938: "dispnew.c", line 896: compiler error: no table entry for op OREG. */ ! 939: char tmp; ! 940: tmp = new_screen->highlight[vpos]; ! 941: current_screen->highlight[vpos] = tmp; ! 942: } ! 943: #endif ! 944: ! 945: if (!new_screen->enable[vpos]) ! 946: { ! 947: nlen = 0; ! 948: goto just_erase; ! 949: } ! 950: ! 951: nbody = new_screen->contents[vpos]; ! 952: nlen = new_screen->used[vpos]; ! 953: ! 954: /* Pretend trailing spaces are not there at all, ! 955: unless for one reason or another we must write all spaces. */ ! 956: /* We know that the previous character byte contains 0. */ ! 957: if (! new_screen->highlight[vpos]) ! 958: { ! 959: if (!must_write_spaces) ! 960: while (nlen > 0 && nbody[nlen - 1] == ' ') ! 961: nlen--; ! 962: if (nlen == 0) ! 963: goto just_erase; ! 964: } ! 965: else ! 966: { ! 967: /* For an inverse-video line, give it extra trailing spaces ! 968: all the way to the screen edge ! 969: so that the reverse video extends all the way across. */ ! 970: while (nlen < screen_width - 1) ! 971: nbody[nlen++] = ' '; ! 972: } ! 973: ! 974: /* If there's no i/d char, quickly do the best we can without it. */ ! 975: if (!char_ins_del_ok) ! 976: { ! 977: int i,j; ! 978: ! 979: for (i = 0; i < nlen; i++) ! 980: { ! 981: if (i >= olen || nbody[i] != obody[i]) ! 982: { ! 983: /* We found a non-matching char. */ ! 984: move_cursor (vpos, i); ! 985: for (j = 1; (i + j < nlen && ! 986: (i + j >= olen || nbody[i+j] != obody[i+j])); ! 987: j++); ! 988: /* Output this run of non-matching chars. */ ! 989: output_chars (nbody + i, j); ! 990: i += j - 1; ! 991: /* Now find the next non-match. */ ! 992: } ! 993: } ! 994: /* Clear the rest of the line, or the non-clear part of it. */ ! 995: if (olen > nlen) ! 996: { ! 997: move_cursor (vpos, nlen); ! 998: clear_end_of_line (olen); ! 999: } ! 1000: ! 1001: /* Exchange contents between current_screen and new_screen. */ ! 1002: temp = new_screen->contents[vpos]; ! 1003: new_screen->contents[vpos] = current_screen->contents[vpos]; ! 1004: current_screen->contents[vpos] = temp; ! 1005: return; ! 1006: } ! 1007: ! 1008: if (!olen) ! 1009: { ! 1010: nsp = (must_write_spaces || new_screen->highlight[vpos]) ! 1011: ? 0 : count_blanks (nbody); ! 1012: if (nlen > nsp) ! 1013: { ! 1014: move_cursor (vpos, nsp); ! 1015: output_chars (nbody + nsp, nlen - nsp); ! 1016: } ! 1017: ! 1018: /* Exchange contents between current_screen and new_screen. */ ! 1019: temp = new_screen->contents[vpos]; ! 1020: new_screen->contents[vpos] = current_screen->contents[vpos]; ! 1021: current_screen->contents[vpos] = temp; ! 1022: return; ! 1023: } ! 1024: ! 1025: obody[olen] = 1; ! 1026: save = nbody[nlen]; ! 1027: nbody[nlen] = 0; ! 1028: ! 1029: /* Compute number of leading blanks in old and new contents. */ ! 1030: osp = count_blanks (obody); ! 1031: if (!new_screen->highlight[vpos]) ! 1032: nsp = count_blanks (nbody); ! 1033: else ! 1034: nsp = 0; ! 1035: ! 1036: /* Compute number of matching chars starting with first nonblank. */ ! 1037: begmatch = count_match (obody + osp, nbody + nsp); ! 1038: ! 1039: /* Spaces in new match implicit space past the end of old. */ ! 1040: /* A bug causing this to be a no-op was fixed in 18.29. */ ! 1041: if (!must_write_spaces && osp + begmatch == olen) ! 1042: { ! 1043: np1 = nbody + nsp; ! 1044: while (np1[begmatch] == ' ') ! 1045: begmatch++; ! 1046: } ! 1047: ! 1048: /* Avoid doing insert/delete char ! 1049: just cause number of leading spaces differs ! 1050: when the following text does not match. */ ! 1051: if (begmatch == 0 && osp != nsp) ! 1052: osp = nsp = min (osp, nsp); ! 1053: ! 1054: /* Find matching characters at end of line */ ! 1055: op1 = obody + olen; ! 1056: np1 = nbody + nlen; ! 1057: op2 = op1 + begmatch - min (olen - osp, nlen - nsp); ! 1058: while (op1 > op2 && op1[-1] == np1[-1]) ! 1059: { ! 1060: op1--; ! 1061: np1--; ! 1062: } ! 1063: endmatch = obody + olen - op1; ! 1064: ! 1065: /* Put correct value back in nbody[nlen]. ! 1066: This is important because direct_output_for_insert ! 1067: can write into the line at a later point. */ ! 1068: nbody[nlen] = save; ! 1069: /* Likewise, make sure that the null after the usable space in obody ! 1070: always remains a null. */ ! 1071: obody[olen] = 0; ! 1072: ! 1073: /* tem gets the distance to insert or delete. ! 1074: endmatch is how many characters we save by doing so. ! 1075: Is it worth it? */ ! 1076: ! 1077: tem = (nlen - nsp) - (olen - osp); ! 1078: if (endmatch && tem && endmatch <= DCICcost[tem]) ! 1079: endmatch = 0; ! 1080: ! 1081: /* nsp - osp is the distance to insert or delete. ! 1082: begmatch + endmatch is how much we save by doing so. ! 1083: Is it worth it? */ ! 1084: ! 1085: if (begmatch + endmatch > 0 && nsp != osp ! 1086: && begmatch + endmatch <= DCICcost[nsp - osp]) ! 1087: { ! 1088: begmatch = 0; ! 1089: endmatch = 0; ! 1090: osp = nsp = min (osp, nsp); ! 1091: } ! 1092: ! 1093: /* Now go through the line, inserting, writing and deleting as appropriate. */ ! 1094: ! 1095: if (osp > nsp) ! 1096: { ! 1097: move_cursor (vpos, nsp); ! 1098: delete_chars (osp - nsp); ! 1099: } ! 1100: else if (nsp > osp) ! 1101: { ! 1102: /* If going to delete chars later in line ! 1103: and insert earlier in the line, ! 1104: must delete first to avoid losing data in the insert */ ! 1105: if (endmatch && nlen < olen + nsp - osp) ! 1106: { ! 1107: move_cursor (vpos, nlen - endmatch + osp - nsp); ! 1108: delete_chars (olen + nsp - osp - nlen); ! 1109: olen = nlen - (nsp - osp); ! 1110: } ! 1111: move_cursor (vpos, osp); ! 1112: insert_chars ((char *)0, nsp - osp); ! 1113: } ! 1114: olen += nsp - osp; ! 1115: ! 1116: tem = nsp + begmatch + endmatch; ! 1117: if (nlen != tem || olen != tem) ! 1118: { ! 1119: move_cursor (vpos, nsp + begmatch); ! 1120: if (!endmatch || nlen == olen) ! 1121: { ! 1122: /* If new text being written reaches right margin, ! 1123: there is no need to do clear-to-eol at the end. ! 1124: (and it would not be safe, since cursor is not ! 1125: going to be "at the margin" after the text is done) */ ! 1126: if (nlen == screen_width) ! 1127: olen = 0; ! 1128: output_chars (nbody + nsp + begmatch, nlen - tem); ! 1129: #ifdef obsolete ! 1130: /* the following code loses disastrously if tem == nlen. ! 1131: Rather than trying to fix that case, I am trying the simpler ! 1132: solution found above. */ ! 1133: /* If the text reaches to the right margin, ! 1134: it will lose one way or another (depending on AutoWrap) ! 1135: to clear to end of line after outputting all the text. ! 1136: So pause with one character to go and clear the line then. */ ! 1137: if (nlen == screen_width && fast_clear_end_of_line && olen > nlen) ! 1138: { ! 1139: /* endmatch must be zero, and tem must equal nsp + begmatch */ ! 1140: output_chars (nbody + tem, nlen - tem - 1); ! 1141: clear_end_of_line (olen); ! 1142: olen = 0; /* Don't let it be cleared again later */ ! 1143: output_chars (nbody + nlen - 1, 1); ! 1144: } ! 1145: else ! 1146: output_chars (nbody + nsp + begmatch, nlen - tem); ! 1147: #endif ! 1148: } ! 1149: else if (nlen > olen) ! 1150: { ! 1151: output_chars (nbody + nsp + begmatch, olen - tem); ! 1152: insert_chars (nbody + nsp + begmatch + olen - tem, nlen - olen); ! 1153: olen = nlen; ! 1154: } ! 1155: else if (olen > nlen) ! 1156: { ! 1157: output_chars (nbody + nsp + begmatch, nlen - tem); ! 1158: delete_chars (olen - nlen); ! 1159: olen = nlen; ! 1160: } ! 1161: } ! 1162: ! 1163: just_erase: ! 1164: /* If any unerased characters remain after the new line, erase them. */ ! 1165: if (olen > nlen) ! 1166: { ! 1167: move_cursor (vpos, nlen); ! 1168: clear_end_of_line (olen); ! 1169: } ! 1170: ! 1171: /* Exchange contents between current_screen and new_screen. */ ! 1172: temp = new_screen->contents[vpos]; ! 1173: new_screen->contents[vpos] = current_screen->contents[vpos]; ! 1174: current_screen->contents[vpos] = temp; ! 1175: } ! 1176: ! 1177: count_blanks (str) ! 1178: char *str; ! 1179: { ! 1180: register char *p = str; ! 1181: while (*str++ == ' '); ! 1182: return str - p - 1; ! 1183: } ! 1184: ! 1185: count_match (str1, str2) ! 1186: char *str1, *str2; ! 1187: { ! 1188: register char *p1 = str1; ! 1189: register char *p2 = str2; ! 1190: while (*p1++ == *p2++); ! 1191: return p1 - str1 - 1; ! 1192: } ! 1193: ! 1194: DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript, ! 1195: 1, 1, "FOpen termscript file: ", ! 1196: "Start writing all terminal output to FILE as well as the terminal.\n\ ! 1197: FILE = nil means just close any termscript file currently open.") ! 1198: (file) ! 1199: Lisp_Object file; ! 1200: { ! 1201: if (termscript != 0) fclose (termscript); ! 1202: termscript = 0; ! 1203: ! 1204: if (! NULL (file)) ! 1205: { ! 1206: file = Fexpand_file_name (file, Qnil); ! 1207: termscript = fopen (XSTRING (file)->data, "w"); ! 1208: if (termscript == 0) ! 1209: report_file_error ("Opening termscript", Fcons (file, Qnil)); ! 1210: } ! 1211: return Qnil; ! 1212: } ! 1213: ! 1214: DEFUN ("set-screen-height", Fset_screen_height, Sset_screen_height, 1, 2, 0, ! 1215: "Tell redisplay that the screen has LINES lines.\n\ ! 1216: Optional second arg non-nil means that redisplay should use LINES lines\n\ ! 1217: but that the idea of the actual height of the screen should not be changed.") ! 1218: (n, pretend) ! 1219: Lisp_Object n, pretend; ! 1220: { ! 1221: CHECK_NUMBER (n, 0); ! 1222: change_screen_size (XINT (n), 0, !NULL (pretend), 0, 0); ! 1223: return Qnil; ! 1224: } ! 1225: ! 1226: DEFUN ("set-screen-width", Fset_screen_width, Sset_screen_width, 1, 2, 0, ! 1227: "Tell redisplay that the screen has COLS columns.\n\ ! 1228: Optional second arg non-nil means that redisplay should use COLS columns\n\ ! 1229: but that the idea of the actual width of the screen should not be changed.") ! 1230: (n, pretend) ! 1231: Lisp_Object n, pretend; ! 1232: { ! 1233: CHECK_NUMBER (n, 0); ! 1234: change_screen_size (0, XINT (n), !NULL (pretend), 0, 0); ! 1235: return Qnil; ! 1236: } ! 1237: ! 1238: DEFUN ("screen-height", Fscreen_height, Sscreen_height, 0, 0, 0, ! 1239: "Return number of lines on screen available for display.") ! 1240: () ! 1241: { ! 1242: return make_number (screen_height); ! 1243: } ! 1244: ! 1245: DEFUN ("screen-width", Fscreen_width, Sscreen_width, 0, 0, 0, ! 1246: "Return number of columns on screen available for display.") ! 1247: () ! 1248: { ! 1249: return make_number (screen_width); ! 1250: } ! 1251: ! 1252: #ifdef SIGWINCH ! 1253: window_change_signal () ! 1254: { ! 1255: int width, height; ! 1256: extern int errno; ! 1257: int old_errno = errno; ! 1258: ! 1259: get_screen_size (&width, &height); ! 1260: /* Record the new size, but don't reallocate the data structures now. ! 1261: Let that be done later outside of the signal handler. */ ! 1262: change_screen_size (height, width, 0, 1, 0); ! 1263: signal (SIGWINCH, window_change_signal); ! 1264: ! 1265: errno = old_errno; ! 1266: } ! 1267: #endif /* SIGWINCH */ ! 1268: ! 1269: /* Do any change in screen size that was requested by a signal. */ ! 1270: ! 1271: do_pending_window_change () ! 1272: { ! 1273: /* If change_screen_size should have run before, run it now. */ ! 1274: while (delayed_size_change) ! 1275: { ! 1276: int newwidth = delayed_screen_width; ! 1277: int newheight = delayed_screen_height; ! 1278: delayed_size_change = 0; ! 1279: change_screen_size_1 (newheight, newwidth, 0, 0); ! 1280: } ! 1281: } ! 1282: ! 1283: /* Change the screen height and/or width. Values may be given as zero to ! 1284: indicate no change is to take place. ! 1285: ! 1286: PRETEND is normally 0; 1 means change used-size only but don't ! 1287: change the size used for calculations; -1 means don't redisplay. ! 1288: ! 1289: If DELAYED, don't change the screen size now; just record the new ! 1290: size and do the actual change at a more convenient time. The ! 1291: SIGWINCH handler and the X Windows ConfigureNotify code use this, ! 1292: because they can both be called at inconvenient times. ! 1293: ! 1294: FORCE means finish redisplay now regardless of pending input. ! 1295: This is effective only is DELAYED is not set. */ ! 1296: ! 1297: change_screen_size (newlength, newwidth, pretend, delayed, force) ! 1298: register int newlength, newwidth, pretend, delayed, force; ! 1299: { ! 1300: /* Don't queue a size change if we won't really do anything. */ ! 1301: if ((newlength == 0 || newlength == screen_height) ! 1302: && (newwidth == 0 || newwidth == screen_width)) ! 1303: return; ! 1304: /* If we can't deal with the change now, queue it for later. */ ! 1305: if (delayed) ! 1306: { ! 1307: delayed_screen_width = newwidth; ! 1308: delayed_screen_height = newlength; ! 1309: delayed_size_change = 1; ! 1310: } ! 1311: else ! 1312: { ! 1313: delayed_size_change = 0; ! 1314: change_screen_size_1 (newlength, newwidth, pretend, force); ! 1315: } ! 1316: } ! 1317: ! 1318: change_screen_size_1 (newlength, newwidth, pretend, force) ! 1319: register int newlength, newwidth, pretend, force; ! 1320: { ! 1321: if ((newlength == 0 || newlength == screen_height) ! 1322: && (newwidth == 0 || newwidth == screen_width)) ! 1323: return; ! 1324: if (newlength && newlength != screen_height) ! 1325: { ! 1326: set_window_height (XWINDOW (minibuf_window)->prev, newlength - 1, 0); ! 1327: XFASTINT (XWINDOW (minibuf_window)->top) = newlength - 1; ! 1328: set_window_height (minibuf_window, 1, 0); ! 1329: screen_height = newlength; ! 1330: if (pretend <= 0) ! 1331: ScreenRows = newlength; ! 1332: set_terminal_window (0); ! 1333: } ! 1334: if (newwidth && newwidth != screen_width) ! 1335: { ! 1336: set_window_width (XWINDOW (minibuf_window)->prev, newwidth, 0); ! 1337: set_window_width (minibuf_window, newwidth, 0); ! 1338: screen_width = newwidth; ! 1339: if (pretend <= 0) ! 1340: ScreenCols = newwidth; ! 1341: } ! 1342: remake_screen_structures (); ! 1343: screen_garbaged = 1; ! 1344: calculate_costs (); ! 1345: force_redisplay += force; ! 1346: if (pretend >= 0) ! 1347: redisplay_preserve_echo_area (); ! 1348: force_redisplay -= force; ! 1349: } ! 1350: ! 1351: DEFUN ("baud-rate", Fbaud_rate, Sbaud_rate, 0, 0, 0, ! 1352: "Return the output baud rate of the terminal.") ! 1353: () ! 1354: { ! 1355: Lisp_Object temp; ! 1356: XSET (temp, Lisp_Int, baud_rate); ! 1357: return temp; ! 1358: } ! 1359: ! 1360: DEFUN ("send-string-to-terminal", Fsend_string_to_terminal, ! 1361: Ssend_string_to_terminal, 1, 1, 0, ! 1362: "Send STRING to the terminal without alteration.\n\ ! 1363: Control characters in STRING will have terminal-dependent effects.") ! 1364: (str) ! 1365: Lisp_Object str; ! 1366: { ! 1367: CHECK_STRING (str, 0); ! 1368: fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, stdout); ! 1369: fflush (stdout); ! 1370: if (termscript) ! 1371: { ! 1372: fwrite (XSTRING (str)->data, 1, XSTRING (str)->size, termscript); ! 1373: fflush (termscript); ! 1374: } ! 1375: return Qnil; ! 1376: } ! 1377: ! 1378: DEFUN ("ding", Fding, Sding, 0, 1, 0, ! 1379: "Beep, or flash the screen.\n\ ! 1380: Terminates any keyboard macro currently executing unless an argument\n\ ! 1381: is given.") ! 1382: (arg) ! 1383: Lisp_Object arg; ! 1384: { ! 1385: if (!NULL (arg)) ! 1386: { ! 1387: if (noninteractive) ! 1388: putchar (07); ! 1389: else ! 1390: ring_bell (); ! 1391: fflush (stdout); ! 1392: } ! 1393: else ! 1394: bell (); ! 1395: return Qnil; ! 1396: } ! 1397: ! 1398: bell () ! 1399: { ! 1400: if (noninteractive) ! 1401: putchar (07); ! 1402: else if (!FROM_KBD) /* Stop executing a keyboard macro. */ ! 1403: error ("Keyboard macro terminated by a command ringing the bell"); ! 1404: else ! 1405: ring_bell (); ! 1406: fflush (stdout); ! 1407: } ! 1408: ! 1409: DEFUN ("sleep-for", Fsleep_for, Ssleep_for, 1, 1, 0, ! 1410: "Pause, without updating display, for ARG seconds.") ! 1411: (n) ! 1412: Lisp_Object n; ! 1413: { ! 1414: register int t; ! 1415: #ifndef subprocesses ! 1416: #ifdef HAVE_TIMEVAL ! 1417: struct timeval timeout, end_time, garbage1; ! 1418: #endif /* HAVE_TIMEVAL */ ! 1419: #endif /* no subprocesses */ ! 1420: ! 1421: CHECK_NUMBER (n, 0); ! 1422: t = XINT (n); ! 1423: if (t <= 0) ! 1424: return Qnil; ! 1425: ! 1426: #ifdef subprocesses ! 1427: wait_reading_process_input (t, 0, 0); ! 1428: #else /* No subprocesses */ ! 1429: immediate_quit = 1; ! 1430: QUIT; ! 1431: ! 1432: #ifdef VMS ! 1433: sys_sleep (t); ! 1434: #else /* not VMS */ ! 1435: /* The reason this is done this way ! 1436: (rather than defined (H_S) && defined (H_T)) ! 1437: is because the VMS preprocessor doesn't grok `defined' */ ! 1438: #ifdef HAVE_SELECT ! 1439: #ifdef HAVE_TIMEVAL ! 1440: gettimeofday (&end_time, &garbage1); ! 1441: end_time.tv_sec += t; ! 1442: ! 1443: while (1) ! 1444: { ! 1445: gettimeofday (&timeout, &garbage1); ! 1446: ! 1447: /* In effect, timeout = end_time - timeout. ! 1448: Break if result would be negative. */ ! 1449: if (timeval_subtract (&timeout, end_time, timeout)) ! 1450: break; ! 1451: ! 1452: if (!select (1, 0, 0, 0, &timeout)) ! 1453: break; ! 1454: } ! 1455: #else /* not HAVE_TIMEVAL */ ! 1456: /* Is it safe to quit out of `sleep'? I'm afraid to trust it. */ ! 1457: sleep (t); ! 1458: #endif /* HAVE_TIMEVAL */ ! 1459: #else /* not HAVE_SELECT */ ! 1460: sleep (t); ! 1461: #endif /* HAVE_SELECT */ ! 1462: #endif /* not VMS */ ! 1463: ! 1464: immediate_quit = 0; ! 1465: #endif /* no subprocesses */ ! 1466: return Qnil; ! 1467: } ! 1468: ! 1469: #ifdef HAVE_TIMEVAL ! 1470: ! 1471: /* Subtract the `struct timeval' values X and Y, ! 1472: storing the result in RESULT. ! 1473: Return 1 if the difference is negative, otherwise 0. */ ! 1474: ! 1475: int ! 1476: timeval_subtract (result, x, y) ! 1477: struct timeval *result, x, y; ! 1478: { ! 1479: /* Perform the carry for the later subtraction by updating y. ! 1480: This is safer because on some systems ! 1481: the tv_sec member is unsigned. */ ! 1482: if (x.tv_usec < y.tv_usec) ! 1483: { ! 1484: int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1; ! 1485: y.tv_usec -= 1000000 * nsec; ! 1486: y.tv_sec += nsec; ! 1487: } ! 1488: if (x.tv_usec - y.tv_usec > 1000000) ! 1489: { ! 1490: int nsec = (y.tv_usec - x.tv_usec) / 1000000; ! 1491: y.tv_usec += 1000000 * nsec; ! 1492: y.tv_sec -= nsec; ! 1493: } ! 1494: ! 1495: /* Compute the time remaining to wait. tv_usec is certainly positive. */ ! 1496: result->tv_sec = x.tv_sec - y.tv_sec; ! 1497: result->tv_usec = x.tv_usec - y.tv_usec; ! 1498: ! 1499: /* Return indication of whether the result should be considered negative. */ ! 1500: return x.tv_sec < y.tv_sec; ! 1501: } ! 1502: #endif /* HAVE_TIMEVAL */ ! 1503: ! 1504: DEFUN ("sit-for", Fsit_for, Ssit_for, 1, 2, 0, ! 1505: "Perform redisplay, then wait for ARG seconds or until input is available.\n\ ! 1506: Optional second arg non-nil means don't redisplay.\n\ ! 1507: Redisplay is preempted as always if input arrives, and does not happen\n\ ! 1508: if input is available before it starts.\n\ ! 1509: Value is t if waited the full time with no input arriving.") ! 1510: (n, nodisp) ! 1511: Lisp_Object n, nodisp; ! 1512: { ! 1513: #ifndef subprocesses ! 1514: #ifdef HAVE_TIMEVAL ! 1515: struct timeval timeout; ! 1516: #else ! 1517: int timeout_sec; ! 1518: #endif ! 1519: int waitchannels; ! 1520: #endif /* no subprocesses */ ! 1521: ! 1522: CHECK_NUMBER (n, 0); ! 1523: ! 1524: if (detect_input_pending ()) ! 1525: return Qnil; ! 1526: ! 1527: if (EQ (nodisp, Qnil)) ! 1528: redisplay_preserve_echo_area (); ! 1529: if (XINT (n) > 0) ! 1530: { ! 1531: #ifdef subprocesses ! 1532: #ifdef SIGIO ! 1533: gobble_input (); ! 1534: #endif /* SIGIO */ ! 1535: wait_reading_process_input (XINT (n), 1, 1); ! 1536: #else /* not subprocesses */ ! 1537: immediate_quit = 1; ! 1538: QUIT; ! 1539: ! 1540: waitchannels = 1; ! 1541: #ifdef VMS ! 1542: input_wait_timeout (XINT (n)); ! 1543: #else /* not VMS */ ! 1544: #ifndef HAVE_TIMEVAL ! 1545: timeout_sec = XINT (n); ! 1546: select (1, &waitchannels, 0, 0, &timeout_sec); ! 1547: #else /* HAVE_TIMEVAL */ ! 1548: timeout.tv_sec = XINT (n); ! 1549: timeout.tv_usec = 0; ! 1550: select (1, &waitchannels, 0, 0, &timeout); ! 1551: #endif /* HAVE_TIMEVAL */ ! 1552: #endif /* not VMS */ ! 1553: ! 1554: immediate_quit = 0; ! 1555: #endif /* not subprocesses */ ! 1556: } ! 1557: return detect_input_pending () ? Qnil : Qt; ! 1558: } ! 1559: ! 1560: char *terminal_type; ! 1561: ! 1562: /* Initialization done when Emacs fork is started, before doing stty. */ ! 1563: /* Determine terminal type and set terminal_driver */ ! 1564: /* Then invoke its decoding routine to set up variables ! 1565: in the terminal package */ ! 1566: ! 1567: init_display () ! 1568: { ! 1569: #ifdef HAVE_X_WINDOWS ! 1570: extern Lisp_Object Vxterm; ! 1571: Vxterm = Qnil; ! 1572: #endif ! 1573: ! 1574: Vwindow_system = Qnil; ! 1575: meta_key = 0; ! 1576: inverse_video = 0; ! 1577: cursor_in_echo_area = 0; ! 1578: terminal_type = (char *) 0; ! 1579: ! 1580: if (!inhibit_window_system) ! 1581: { ! 1582: #ifdef HAVE_X_WINDOWS ! 1583: extern char *alternate_display; ! 1584: char *disp = (char *) egetenv ("DISPLAY"); ! 1585: ! 1586: /* Note KSH likes to provide an empty string as an envvar value. */ ! 1587: if (alternate_display || (disp && *disp)) ! 1588: { ! 1589: x_term_init (); ! 1590: Vxterm = Qt; ! 1591: Vwindow_system = intern ("x"); ! 1592: #ifdef X11 ! 1593: Vwindow_system_version = make_number (11); ! 1594: #else ! 1595: Vwindow_system_version = make_number (10); ! 1596: #endif ! 1597: goto term_init_done; ! 1598: } ! 1599: #endif /* HAVE_X_WINDOWS */ ! 1600: ; ! 1601: } ! 1602: /* Record we aren't using a window system. */ ! 1603: inhibit_window_system = 1; ! 1604: ! 1605: /* Look at the TERM variable */ ! 1606: terminal_type = (char *) getenv ("TERM"); ! 1607: if (!terminal_type) ! 1608: { ! 1609: #ifdef VMS ! 1610: fprintf (stderr, "Please specify your terminal type.\n\ ! 1611: For types defined in VMS, use set term /device=TYPE.\n\ ! 1612: For types not defined in VMS, use define emacs_term \"TYPE\".\n\ ! 1613: \(The quotation marks are necessary since terminal types are lower case.)\n"); ! 1614: #else ! 1615: fprintf (stderr, "Please set the environment variable TERM; see tset(1).\n"); ! 1616: #endif ! 1617: exit (1); ! 1618: } ! 1619: term_init (terminal_type); ! 1620: ! 1621: term_init_done: ! 1622: remake_screen_structures (); ! 1623: calculate_costs (); ! 1624: ! 1625: #ifdef SIGWINCH ! 1626: #ifndef CANNOT_DUMP ! 1627: if (initialized) ! 1628: #endif /* CANNOT_DUMP */ ! 1629: if (inhibit_window_system) ! 1630: signal (SIGWINCH, window_change_signal); ! 1631: #endif /* SIGWINCH */ ! 1632: } ! 1633: ! 1634: syms_of_display () ! 1635: { ! 1636: defsubr (&Sopen_termscript); ! 1637: defsubr (&Sding); ! 1638: defsubr (&Ssit_for); ! 1639: defsubr (&Sscreen_height); ! 1640: defsubr (&Sscreen_width); ! 1641: defsubr (&Sset_screen_height); ! 1642: defsubr (&Sset_screen_width); ! 1643: defsubr (&Ssleep_for); ! 1644: defsubr (&Sbaud_rate); ! 1645: defsubr (&Ssend_string_to_terminal); ! 1646: ! 1647: DEFVAR_BOOL ("inverse-video", &inverse_video, ! 1648: "*Non-nil means use inverse-video."); ! 1649: DEFVAR_BOOL ("visible-bell", &visible_bell, ! 1650: "*Non-nil means try to flash the screen to represent a bell.\n\ ! 1651: Note: for X windows, you must use x-set-bell instead."); ! 1652: DEFVAR_BOOL ("no-redraw-on-reenter", &no_redraw_on_reenter, ! 1653: "*Non-nil means no need to redraw entire screen after suspending.\n\ ! 1654: It is up to you to set this variable to inform Emacs."); ! 1655: DEFVAR_LISP ("window-system", &Vwindow_system, ! 1656: "A symbol naming the window-system under which Emacs is running,\n\ ! 1657: \(such as `x'), or nil if emacs is running on an ordinary terminal."); ! 1658: DEFVAR_LISP ("window-system-version", &Vwindow_system_version, ! 1659: "Version number of the window system Emacs is running under."); ! 1660: DEFVAR_BOOL ("cursor-in-echo-area", &cursor_in_echo_area, ! 1661: "Non-nil means put cursor in minibuffer after any message displayed there."); ! 1662: ! 1663: /* Initialize `window-system', unless init_display already decided it. */ ! 1664: #ifdef CANNOT_DUMP ! 1665: if (noninteractive) ! 1666: #endif ! 1667: { ! 1668: Vwindow_system_version = Qnil; ! 1669: Vwindow_system = Qnil; ! 1670: } ! 1671: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.