1: /* Display generation from window structure and buffer text. 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 "config.h" 23: #include <stdio.h> 24: #include <ctype.h> 25: #undef NULL 26: #include "lisp.h" 27: #include "window.h" 28: #include "termchar.h" 29: #include "dispextern.h" 30: #include "buffer.h" 31: #include "indent.h" 32: #include "commands.h" 33: #include "macros.h" 34: 35: extern int interrupt_input; 36: 37: /* Nonzero means print newline before next minibuffer message. */ 38: 39: int noninteractive_need_newline; 40: 41: #define min(a, b) ((a) < (b) ? (a) : (b)) 42: #define max(a, b) ((a) > (b) ? (a) : (b)) 43: 44: #define CURRENT_END_POS(w) \ 45: (XFASTINT (w->window_end_pos) < 0 \ 46: ? -1 - XFASTINT(w->window_end_pos) \ 47: : XFASTINT(w->window_end_pos)) 48: 49: /* The buffer position of the first character appearing 50: entirely or partially on the current screen line. 51: Or zero, which disables the optimization for the current screen line. */ 52: int this_line_bufpos; 53: 54: /* Number of characters past the end of this line, 55: including the terminating newline */ 56: int this_line_endpos; 57: 58: /* The vertical position of this screen line. */ 59: int this_line_vpos; 60: 61: /* Hpos value for start of display on this screen line. 62: Usually zero, but negative if first character really began on previous line */ 63: int this_line_hpos; 64: 65: /* Buffer that this_line variables are describing. */ 66: struct buffer *this_line_buffer; 67: 68: /* Value of minibuf_message when it was last acted on. 69: If this is nonzero, there is a message on the screen 70: in the minibuffer and it should be erased as soon 71: as it is no longer requested to appear. */ 72: char *prev_minibuf_message; 73: 74: /* Nonzero means truncate lines in all windows less wide than the screen */ 75: 76: int truncate_partial_width_windows; 77: 78: Lisp_Object Vglobal_mode_string; 79: 80: Lisp_Object Vglobal_minor_modes; 81: 82: /* The number of lines to try scrolling a 83: window by when point leaves the window; if 84: it is <=0 then point is centered in the window */ 85: int scroll_step; 86: 87: /* Nonzero if try_window_id has made blank lines at window bottom 88: since the last redisplay that paused */ 89: int blank_end_of_window; 90: 91: /* Number of windows showing the buffer of the selected window. */ 92: static int buffer_shared; 93: 94: /* display_text_line sets these to the screen position (origin 0) of point, 95: whether the window is selected or not. 96: Set one to -1 first to determine whether point was found afterwards. */ 97: 98: int point_vpos; 99: int point_hpos; 100: 101: int debug_end_pos; 102: 103: extern int default_ctl_arrow; /* Nonzero means display ctl chars */ 104: /* with uparrow in mode lines, etc */ 105: 106: int mode_line_inverse_video; /* Nonzero means display mode line highlighted */ 107: 108: struct position *display_text_line (); 109: 110: char *minibuf_prompt; /* Prompt to display in front of the minibuffer contents */ 111: 112: /* Width in columns of current minibuffer prompt. */ 113: 114: int minibuf_prompt_width; 115: 116: char *minibuf_message; /* Message to display instead of minibuffer contents 117: This is what the functions error and message make, 118: and command echoing uses it as well. 119: It overrides the minibuf_prompt as well as the buffer. */ 120: 121: int RecurseDepth; /* Depth in recursive edits */ 122: 123: int MinibufDepth; /* Depth in minibuffer invocations */ 124: 125: int RedoModes; /* true iff we should redraw the mode lines 126: on the next redisplay */ 127: 128: /* Minimum value of bf_s1 since last redisplay that finished. 129: Valid for current buffer unless Cant1WinOpt is nonzero. */ 130: 131: int beg_unchanged; 132: 133: /* Minimum value of bf_s2 since last redisplay that finished. 134: Valid for current buffer unless Cant1WinOpt is nonzero. */ 135: 136: int end_unchanged; 137: 138: /* bf_modified as of last redisplay that finished; 139: if it matches bf_modified, beg_unchanged and end_unchanged 140: contain no useful information */ 141: int unchanged_modified; 142: 143: /* Nonzero if head_clip or tail_clip of current buffer has changed 144: since last redisplay that finished */ 145: int clip_changed; 146: 147: /* Nonzero if window sizes or contents have changed 148: since last redisplay that finished */ 149: int windows_or_buffers_changed; 150: 151: DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "", 152: "Clear the screen and output again what is supposed to appear on it.") 153: () 154: { 155: if (screen_height == 0) abort (); /* Some bug zeros some core */ 156: set_terminal_modes (); 157: clear_screen (); 158: fflush (stdout); 159: clear_screen_records (); 160: if (screen_height == 0) abort (); /* Some bug zeros some core */ 161: windows_or_buffers_changed++; 162: /* Mark all windows as INaccurate, 163: so that every window will have its redisplay done. */ 164: mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 0); 165: if (screen_height == 0) abort (); /* Some bug zeros some core */ 166: return Qnil; 167: } 168: 169: static char message_buf[MScreenWidth + 1]; 170: 171: /* dump an informative message to the minibuf */ 172: /* VARARGS 1 */ 173: message (m, a1, a2, a3) 174: char *m; 175: { 176: if (noninteractive) 177: { 178: if (noninteractive_need_newline) 179: putchar ('\n'); 180: printf (m, a1, a2, a3); 181: printf ("\n"); 182: fflush (stdout); 183: } 184: else if (INTERACTIVE) 185: { 186: doprnt (message_buf, sizeof message_buf - 1, m, &a1); 187: minibuf_message = message_buf; 188: display_minibuf_message (); 189: update_screen (1, 1); 190: } 191: } 192: 193: /* Specify m, a string, as a message in the minibuf. */ 194: message1 (m) 195: char *m; 196: { 197: if (noninteractive) 198: { 199: if (noninteractive_need_newline) 200: putchar ('\n'); 201: printf ("%s\n", m); 202: fflush (stdout); 203: } 204: else if (INTERACTIVE) 205: { 206: minibuf_message = m; 207: display_minibuf_message (); 208: update_screen (1, 1); 209: } 210: } 211: 212: display_minibuf_message () 213: { 214: register int vpos; 215: register struct display_line *line; 216: 217: if (screen_garbaged) 218: { 219: Fredraw_display (); 220: screen_garbaged = 0; 221: } 222: 223: if (minibuf_message || !MinibufDepth) 224: { 225: vpos = XFASTINT (XWINDOW (minibuf_window)->top); 226: line = get_display_line (vpos, 0); 227: display_string (XWINDOW (minibuf_window), line, 228: minibuf_message ? minibuf_message : "", 229: 0, 0, 0); 230: 231: /* If desired cursor location is on this line, put it at end of text */ 232: if (cursY == vpos) 233: cursX = line->length; 234: } 235: else if (!EQ (minibuf_window, selected_window)) 236: windows_or_buffers_changed++; 237: 238: if (EQ (minibuf_window, selected_window)) 239: this_line_bufpos = 0; 240: 241: prev_minibuf_message = minibuf_message; 242: } 243: 244: /* Do a screen update, taking possible shortcuts into account. 245: This is the main external entry point for redisplay */ 246: 247: DoDsp (SaveMiniBuf) 248: { 249: register struct window *w = XWINDOW (selected_window); 250: register int pause; 251: int inhibit_hairy_id = 0; 252: int must_finish = 0; 253: int all_windows = 0; 254: register int tlbufpos, tlendpos; 255: struct position pos; 256: extern int input_pending; 257: 258: if (noninteractive) 259: return; 260: 261: if (screen_garbaged) 262: { 263: Fredraw_display (); 264: screen_garbaged = 0; 265: } 266: 267: if (minibuf_message || 268: (prev_minibuf_message && !SaveMiniBuf)) 269: { 270: display_minibuf_message (); 271: must_finish = 1; 272: } 273: 274: if (clip_changed || windows_or_buffers_changed) 275: RedoModes++; 276: 277: /* Detect case that we need to write a star in the mode line. */ 278: if (XFASTINT (w->last_modified) < bf_modified 279: && XFASTINT (w->last_modified) <= bf_cur->save_modified) 280: { 281: w->redo_mode_line = Qt; 282: if (buffer_shared > 1) 283: RedoModes++; 284: } 285: 286: all_windows = RedoModes || buffer_shared > 1; 287: 288: tlbufpos = this_line_bufpos; 289: tlendpos = this_line_endpos; 290: if (!all_windows && tlbufpos > 0 && NULL (w->redo_mode_line) 291: /* Point must be on the line that we have info recorded about */ 292: && point >= tlbufpos 293: && point <= bf_s1 + bf_s2 + 1 - tlendpos 294: /* All text outside that line, including its final newline, 295: must be unchanged */ 296: && (XFASTINT (w->last_modified) >= bf_modified 297: || (beg_unchanged >= tlbufpos - 1 298: && bf_s1 >= tlbufpos - 1 299: && end_unchanged >= tlendpos 300: && bf_s2 >= tlendpos)) 301: /* Make sure recorded data applies to current buffer, etc */ 302: && NULL (w->force_start) 303: && bf_cur == XBUFFER (w->buffer) 304: && this_line_buffer == bf_cur) 305: { 306: if (tlbufpos > FirstCharacter && CharAt (tlbufpos - 1) != '\n' 307: && (tlbufpos == NumCharacters + 1 308: || CharAt (tlbufpos) == '\n')) 309: /* Former continuation line has disappeared by becoming empty */ 310: ; 311: else if (XFASTINT (w->last_modified) < bf_modified 312: || EQ (selected_window, minibuf_window)) 313: { 314: point_vpos = -1; 315: display_text_line (w, tlbufpos, this_line_vpos, this_line_hpos, 316: pos_tab_offset (w, tlbufpos)); 317: /* If line contains point, is not continued, 318: and ends at same distance from eob as before, we win */ 319: if (point_vpos >= 0 && this_line_bufpos 320: && this_line_endpos == tlendpos) 321: { 322: cursX = point_hpos; 323: if (XFASTINT (w->width) != screen_width) 324: preserve_other_columns (w); 325: if (interrupt_input) 326: unrequest_sigio (); 327: goto update; 328: } 329: } 330: else if (point == XFASTINT (w->last_point)) 331: { 332: if (!must_finish) 333: return; 334: goto update; 335: } 336: else 337: { 338: pos = *compute_motion (tlbufpos, 0, 339: XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0, 340: point, 2, - (1 << (SHORTBITS - 1)), 341: XFASTINT (w->width) - 1 342: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width), 343: XINT (w->hscroll), 0); 344: if (pos.vpos < 1) 345: { 346: cursX = max (XFASTINT (w->left), pos.hpos); 347: if (interrupt_input) 348: unrequest_sigio (); 349: goto update; 350: } 351: } 352: /* Text changed drastically or point moved off of line */ 353: cancel_line (this_line_vpos); 354: } 355: 356: this_line_bufpos = 0; 357: 358: if (interrupt_input) 359: unrequest_sigio (); 360: 361: if (all_windows) 362: redisplay_all_windows (); 363: else 364: { 365: inhibit_hairy_id = redisplay_window (selected_window, 1); 366: if (XFASTINT (w->width) != screen_width) 367: preserve_other_columns (w); 368: } 369: 370: update: 371: pause = update_screen (0, inhibit_hairy_id); 372: 373: /* If screen does not match, prevent doing single-line-update next time */ 374: if (pause) 375: this_line_bufpos = 0; 376: 377: /* Now text on screen agrees with windows, so 378: put info into the windows for partial redisplay to follow */ 379: 380: if (!pause) 381: { 382: register struct buffer_text *t 383: = XBUFFER (w->buffer) == bf_cur 384: ? &bf_text : &XBUFFER (w->buffer)->text; 385: 386: blank_end_of_window = 0; 387: clip_changed = 0; 388: unchanged_modified = t->modified; 389: beg_unchanged = t->size1, end_unchanged = t->size2; 390: 391: XFASTINT (w->last_point) = t->pointloc; 392: XFASTINT (w->last_point_x) = cursX; 393: XFASTINT (w->last_point_y) = cursY; 394: 395: if (all_windows) 396: mark_window_display_accurate (XWINDOW (minibuf_window)->prev, 1); 397: else 398: { 399: w->redo_mode_line = Qnil; 400: XFASTINT (w->last_modified) = t->modified; 401: if (XFASTINT (w->window_end_pos) < 0) 402: XFASTINT (w->window_end_pos) = -1 - XFASTINT (w->window_end_pos); 403: } 404: RedoModes = 0; 405: windows_or_buffers_changed = 0; 406: } 407: 408: /* Start SIGIO interrupts coming again. 409: Having them off during the code above 410: makes it less likely one will discard output, 411: but not impossible, since there might be stuff 412: in the system buffer here. 413: But it is much hairier to try to do anything about that. */ 414: 415: if (interrupt_input) 416: request_sigio (); 417: } 418: 419: mark_window_display_accurate (window, flag) 420: Lisp_Object window; 421: int flag; 422: { 423: register struct window *w; 424: 425: for (;!NULL (window); window = w->next) 426: { 427: w = XWINDOW (window); 428: 429: XFASTINT (w->last_modified) 430: = !flag ? 0 431: : XBUFFER (w->buffer) == bf_cur 432: ? bf_modified : XBUFFER (w->buffer)->text.modified; 433: if (XFASTINT (w->window_end_pos) < 0) 434: XFASTINT (w->window_end_pos) = -1 - XFASTINT (w->window_end_pos); 435: w->redo_mode_line = Qnil; 436: 437: if (!NULL (w->vchild)) 438: mark_window_display_accurate (w->vchild, flag); 439: if (!NULL (w->hchild)) 440: mark_window_display_accurate (w->hchild, flag); 441: } 442: } 443: 444: int do_id = 1; 445: 446: /* Do full redisplay of one or all windows. 447: This does not include updating the screen; 448: just generating lines to pass to update_screen. */ 449: 450: /* Entry point to redisplay all windows */ 451: 452: redisplay_all_windows () 453: { 454: buffer_shared = 0; 455: 456: redisplay_windows (XWINDOW (minibuf_window)->prev); 457: } 458: 459: redisplay_windows (window) 460: Lisp_Object window; 461: { 462: for (; !NULL (window); window = XWINDOW (window)->next) 463: redisplay_window (window, 0); 464: } 465: 466: redisplay_window (window, just_this_one) 467: Lisp_Object window; 468: int just_this_one; 469: { 470: register struct window *w = XWINDOW (window); 471: int height; 472: register int lpoint = point; 473: struct buffer *old = bf_cur; 474: register int width = XFASTINT (w->width) - 1 475: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width); 476: register int startp = marker_position (w->start); 477: register int hscroll = XINT (w->hscroll); 478: struct position pos; 479: int inhibit_hairy_id = 0; 480: int opoint; 481: int tem; 482: 483: if (screen_height == 0) abort (); /* Some bug zeros some core */ 484: 485: /* If this is a combination window, do its children; that's all. */ 486: 487: if (!NULL (w->vchild)) 488: { 489: redisplay_windows (w->vchild); 490: return 0; 491: } 492: if (!NULL (w->hchild)) 493: { 494: redisplay_windows (w->hchild); 495: return 0; 496: } 497: if (NULL (w->buffer)) 498: abort (); 499: 500: if (RedoModes) 501: w->redo_mode_line = Qt; 502: 503: /* Otherwise set up data on this window; select its buffer and point value */ 504: 505: height = XFASTINT (w->height); 506: if (w != XWINDOW (minibuf_window)) 507: height--; 508: else if (minibuf_message) 509: return 0; 510: 511: SetBfx (XBUFFER (w->buffer)); 512: opoint = point; 513: 514: if (!just_this_one 515: && bf_cur == XBUFFER (XWINDOW (selected_window)->buffer)) 516: buffer_shared++; 517: 518: if (!EQ (window, selected_window)) 519: { 520: SetPoint (marker_position (w->pointm)); 521: if (point < FirstCharacter) 522: point = FirstCharacter; 523: else if (point > NumCharacters) 524: point = NumCharacters + 1; 525: } 526: 527: /* Handle case where place to start displaying has been specified */ 528: 529: if (!NULL (w->force_start)) 530: { 531: w->redo_mode_line = Qt; 532: w->force_start = Qnil; 533: XFASTINT (w->last_modified) = 0; 534: if (!try_window (window, startp)) 535: { 536: /* If point does not appear, move point so it does appear */ 537: pos = *compute_motion (startp, 0, 538: ((EQ (window, minibuf_window) && startp == 1) 539: ? minibuf_prompt_width : 0) 540: + 541: (hscroll ? 1 - hscroll : 0), 542: NumCharacters + 1, height / 2, 543: - (1 << (SHORTBITS - 1)), 544: width, hscroll, pos_tab_offset (w, startp)); 545: SetPoint (pos.bufpos); 546: if (w != XWINDOW (selected_window)) 547: Fset_marker (w->pointm, make_number (point), Qnil); 548: else 549: lpoint = point; 550: 551: if (EQ (window, selected_window)) 552: { 553: cursX = max (0, pos.hpos) + XFASTINT (w->left); 554: cursY = pos.vpos + XFASTINT (w->top); 555: } 556: } 557: goto done; 558: } 559: 560: /* Handle case where text has not changed, only point, 561: and it has not moved off the screen */ 562: 563: /* This code is not used for minibuffer for the sake of 564: the case of redisplaying to replace an echo area message; 565: since in that case the minibuffer contents per se are usually unchanged. 566: This code is of no real use in the minibuffer since 567: the handling of tlbufpos, etc., in DoDsp handles the same cases. */ 568: 569: if (XFASTINT (w->last_modified) >= bf_modified 570: && point >= startp && !clip_changed 571: && (just_this_one || XFASTINT (w->width) == screen_width) 572: && !EQ (window, minibuf_window)) 573: { 574: pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), 575: point, height + 1, 10000, width, hscroll, 576: pos_tab_offset (w, startp)); 577: 578: if (pos.vpos < height) 579: { 580: /* Ok, point is still on screen */ 581: if (w == XWINDOW (selected_window)) 582: { 583: /* These variables are supposed to be origin 1 */ 584: cursX = max (0, pos.hpos) + XFASTINT (w->left); 585: cursY = pos.vpos + XFASTINT (w->top); 586: } 587: /* This doesn't do the trick, because if a window to the right of 588: this one must be redisplayed, this does nothing because there 589: is nothing in DesiredScreen yet, and then the other window is 590: redisplayed, making likes that are empty in this window's columns. 591: if (XFASTINT (w->width) != screen_width) 592: preserve_my_columns (w); 593: */ 594: goto done; 595: } 596: /* Don't bother trying redisplay with same start; 597: we already know it will lose */ 598: } 599: else if (just_this_one && !EQ (window, minibuf_window) 600: && point >= startp 601: && XFASTINT (w->last_modified) 602: && XFASTINT (w->window_end_pos) >= 0 603: && do_id && !clip_changed 604: && !blank_end_of_window 605: && XFASTINT (w->width) == screen_width 606: && (tem = try_window_id (selected_window)) 607: && tem != -2) 608: { 609: /* tem > 0 means success. tem == -1 means choose new start. 610: tem == -2 means try again with same start, 611: and nothing but whitespace follows the changed stuff. 612: tem == 0 means try again with same start. */ 613: if (tem > 0) 614: { 615: /* inhibit_hairy_id = 1; */ 616: goto done; 617: } 618: } 619: else if (startp >= FirstCharacter && startp <= NumCharacters + 1 620: /* Avoid starting display at end of buffer! */ 621: && (startp <= NumCharacters || startp == FirstCharacter 622: || (XFASTINT (w->last_modified) >= bf_modified))) 623: { 624: /* Try to redisplay starting at same place as before */ 625: /* If point has not moved off screen, accept the results */ 626: if (try_window (window, startp)) 627: goto done; 628: else 629: cancel_my_columns (w); 630: } 631: 632: XFASTINT (w->last_modified) = 0; 633: w->redo_mode_line = Qt; 634: 635: /* Try to scroll by specified few lines */ 636: 637: if (scroll_step && !clip_changed) 638: { 639: if (point > startp) 640: { 641: pos = *vmotion (bf_s1 + bf_s2 + 1 - CURRENT_END_POS (w), 642: scroll_step, width, hscroll, window); 643: if (pos.vpos >= height) 644: goto scroll_fail; 645: } 646: 647: pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step, 648: width, hscroll, window); 649: 650: if (point >= pos.bufpos) 651: { 652: if (try_window (window, pos.bufpos)) 653: goto done; 654: else 655: cancel_my_columns (w); 656: } 657: scroll_fail: ; 658: } 659: 660: /* Finally, just choose place to start which centers point */ 661: 662: pos = *vmotion (point, - height / 2, width, hscroll, window); 663: try_window (window, pos.bufpos); 664: 665: done: 666: /* If window not full width, must redo its mode line 667: if the window to its side is being redone */ 668: if ((!NULL (w->redo_mode_line) 669: || (!just_this_one && width < screen_width - 1)) 670: && !EQ (window, minibuf_window)) 671: display_mode_line (w); 672: 673: SetPoint (opoint); 674: SetBfx (old); 675: SetPoint (lpoint); 676: 677: return inhibit_hairy_id; 678: } 679: 680: /* Do full redisplay on one window, 681: starting at position `pos', 682: and return nonzero if point appears in the displayed text */ 683: 684: try_window (window, pos) 685: Lisp_Object window; 686: register int pos; 687: { 688: register struct window *w = XWINDOW (window); 689: register int height = XFASTINT (w->height) - !EQ (window, minibuf_window); 690: register int vpos = XFASTINT (w->top); 691: register int last_text_vpos = vpos; 692: int tab_offset = pos_tab_offset (w, pos); 693: 694: struct position val; 695: 696: Fset_marker (w->start, make_number (pos), Qnil); 697: 698: point_vpos = -1; 699: val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0; 700: 701: while (--height >= 0) 702: { 703: val = *display_text_line (w, pos, vpos, val.hpos, tab_offset); 704: tab_offset += XFASTINT (w->width) - 1; 705: if (val.vpos) tab_offset = 0; 706: vpos++; 707: if (pos != val.bufpos) 708: last_text_vpos 709: /* Next line, unless prev line ended in end of buffer with no cr */ 710: = vpos - (val.vpos && CharAt (val.bufpos - 1) != '\n'); 711: pos = val.bufpos; 712: } 713: 714: /* If last line is continued in middle of character, 715: include the split character in the text considered on the screen */ 716: if (val.hpos < XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0) 717: pos++; 718: 719: /* Make this -1 minus what it really should be, so that it is negative. 720: That serves as a signal that it is not really valid. 721: When screen updating is through, 722: change this to its correct positive value */ 723: XFASTINT (w->window_end_pos) = -1 - (bf_s1 + bf_s2 + 1 - pos); 724: XFASTINT (w->window_end_vpos) = last_text_vpos - XFASTINT (w->top); 725: return point_vpos >= 0; 726: } 727: 728: /* Try to redisplay when buffer is modified locally, 729: computing insert/delete line to preserve text outside 730: the bounds of the changes. 731: Return 1 if successful, 0 if if cannot tell what to do, 732: or -1 to tell caller to find a new window start, 733: or -2 to tell caller that we did nothing because only whitespace 734: appears below the changed part of the screen. */ 735: 736: try_window_id (window) 737: Lisp_Object window; 738: { 739: int pos; 740: register struct window *w = XWINDOW (window); 741: register int height = XFASTINT (w->height) - !EQ (window, minibuf_window); 742: int top = XFASTINT (w->top); 743: int start = marker_position (w->start); 744: int width = XFASTINT (w->width) - 1 745: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width); 746: int hscroll = XINT (w->hscroll); 747: int lmargin = hscroll > 0 ? 1 - hscroll : 0; 748: register int vpos; 749: register int i, tem; 750: int last_text_vpos = 0; 751: int stop_vpos; 752: 753: struct position val, bp, ep, xp, pp; 754: int scroll_amount = 0; 755: int delta; 756: int tab_offset, epto; 757: 758: if (bf_s1 < beg_unchanged) 759: beg_unchanged = bf_s1; 760: if (bf_s2 < end_unchanged) 761: end_unchanged = bf_s2; 762: 763: if (beg_unchanged + 1 < start) 764: return 0; /* Give up if changes go above top of window */ 765: 766: /* Find position before which nothing is changed. */ 767: bp = *compute_motion (start, 0, lmargin, 768: beg_unchanged + 1, 10000, 10000, width, hscroll, 769: pos_tab_offset (w, start)); 770: if (bp.vpos >= height) 771: return point < bp.bufpos && !bp.contin; 772: 773: vpos = bp.vpos; 774: 775: /* Find beginning of that screen line. Must display from there. */ 776: bp = *vmotion (bp.bufpos, 0, width, hscroll, window); 777: 778: pos = bp.bufpos; 779: val.hpos = lmargin; 780: if (pos < start) 781: return -1; 782: 783: /* If about to start displaying at the beginning of a continuation line, 784: really start with previous screen line, in case it was not 785: continued when last redisplayed */ 786: if (bp.contin && bp.bufpos - 1 == beg_unchanged && vpos > 0) 787: { 788: bp = *vmotion (bp.bufpos, -1, width, hscroll, window); 789: --vpos; 790: pos = bp.bufpos; 791: } 792: 793: if (bp.contin && bp.hpos != lmargin) 794: { 795: val.hpos = bp.prevhpos - width + lmargin; 796: pos--; 797: } 798: 799: bp.vpos = vpos; 800: 801: /* Find first newline after which no more is changed */ 802: ep = *compute_motion (pos, vpos, val.hpos, 803: ScanBf ('\n', 804: bf_s1 + bf_s2 + 1 - max (end_unchanged, bf_tail_clip), 805: 1), 806: height, - (1 << (SHORTBITS - 1)), 807: width, hscroll, pos_tab_offset (w, bp.bufpos)); 808: 809: /* If changes reach past the text available on the screen, 810: just display rest of screen. */ 811: if (ep.bufpos > bf_s1 + bf_s2 + 1 - XFASTINT (w->window_end_pos)) 812: stop_vpos = height; 813: else 814: stop_vpos = ep.vpos; 815: 816: /* If no newline before ep, the line ep is on includes some changes 817: that must be displayed. Make sure we don't stop before it. */ 818: /* Also, if changes reach all the way until ep.bufpos, 819: it is possible that something was deleted after the 820: newline before it, so the following line must be redrawn. */ 821: if (stop_vpos == ep.vpos 822: && (ep.bufpos == FirstCharacter 823: || CharAt (ep.bufpos - 1) != '\n' 824: || ep.bufpos == bf_s1 + bf_s2 + 1 - end_unchanged)) 825: stop_vpos = ep.vpos + 1; 826: 827: point_vpos = -1; 828: 829: /* If changes do not reach to bottom of window, 830: figure out how much to scroll the rest of the window */ 831: if (stop_vpos < height) 832: { 833: /* Now determine how far up or down the rest of the window has moved */ 834: epto = pos_tab_offset (w, ep.bufpos); 835: xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 836: bf_s1 + bf_s2 + 1 - XFASTINT (w->window_end_pos), 837: 10000, 0, width, hscroll, epto); 838: scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos); 839: 840: /* Is everything on screen below the changes whitespace? 841: If so, no scrolling is really necessary. */ 842: for (i = ep.bufpos; i < xp.bufpos; i++) 843: { 844: tem = CharAt (i); 845: if (tem != ' ' && tem != '\n' && tem != '\t') 846: break; 847: } 848: if (i == xp.bufpos) 849: return -2; 850: 851: XFASTINT (w->window_end_vpos) += scroll_amount; 852: 853: /* Before doing any scrolling, verify that point will be on screen. */ 854: if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height)) 855: { 856: if (point <= xp.bufpos) 857: { 858: pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 859: point, height, - (1 << (SHORTBITS - 1)), 860: width, hscroll, epto); 861: } 862: else 863: { 864: pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos, 865: point, height, - (1 << (SHORTBITS - 1)), 866: width, hscroll, pos_tab_offset (w, xp.bufpos)); 867: } 868: if (pp.bufpos < point || pp.vpos == height) 869: return 0; 870: point_vpos = pp.vpos + top; 871: point_hpos = pp.hpos + XFASTINT (w->left); 872: } 873: 874: if (stop_vpos - scroll_amount >= height 875: || ep.bufpos == xp.bufpos) 876: { 877: if (scroll_amount < 0) 878: stop_vpos -= scroll_amount; 879: scroll_amount = 0; 880: /* In this path, we have altered window_end_vpos 881: and not left it negative. 882: We must make sure that, in case display is preempted 883: before the screen changes to reflect what we do here, 884: further updates will not come to try_window_id 885: and assume the screen and window_end_vpos match. */ 886: blank_end_of_window = 1; 887: } 888: else if (!scroll_amount) 889: {} 890: else if (bp.bufpos == bf_s1 + bf_s2 + 1 - end_unchanged) 891: { 892: /* If pure deletion, scroll up as many lines as possible. 893: In common case of killing a line, this can save the 894: following line from being overwritten by scrolling 895: and therefore having to be redrawn. */ 896: tem = scroll_screen_lines (bp.vpos + top - scroll_amount, 897: top + height - max (0, scroll_amount), 898: scroll_amount); 899: if (!tem) stop_vpos = height; 900: } 901: else if (scroll_amount) 902: { 903: tem = scroll_screen_lines (ep.vpos + top - scroll_amount, 904: top + height - max (0, scroll_amount), 905: scroll_amount); 906: if (!tem) stop_vpos = height; 907: } 908: } 909: 910: /* In any case, do not display past bottom of window */ 911: if (stop_vpos >= height) 912: { 913: stop_vpos = height; 914: scroll_amount = 0; 915: } 916: 917: /* Handle case where pos is before w->start -- 918: can happen if part of line had been clipped and is not clipped now */ 919: if (vpos == 0 && pos < marker_position (w->start)) 920: Fset_marker (w->start, make_number (pos), Qnil); 921: 922: /* Redisplay the lines where the text was changed */ 923: last_text_vpos = vpos; 924: tab_offset = pos_tab_offset (w, pos); 925: if (val.hpos < 0) 926: tab_offset += XFASTINT (w->width) - 1; 927: while (vpos < stop_vpos) 928: { 929: val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset); 930: tab_offset += XFASTINT (w->width) - 1; 931: if (val.vpos) tab_offset = 0; 932: if (pos != val.bufpos) 933: last_text_vpos 934: /* Next line, unless prev line ended in end of buffer with no cr */ 935: = vpos - (val.vpos && CharAt (val.bufpos - 1) != '\n'); 936: pos = val.bufpos; 937: } 938: 939: /* There are two cases: 940: 1) we have displayed down to the bottom of the window 941: 2) we have scrolled lines below stop_vpos by scroll_amount */ 942: 943: if (vpos == height) 944: { 945: /* If last line is continued in middle of character, 946: include the split character in the text considered on the screen */ 947: if (val.hpos < lmargin) 948: val.bufpos++; 949: XFASTINT (w->window_end_vpos) = last_text_vpos; 950: XFASTINT (w->window_end_pos) = -1 - (bf_s1 + bf_s2 + 1 - val.bufpos); 951: } 952: 953: /* If scrolling made blank lines at window bottom, 954: redisplay to fill those lines */ 955: if (scroll_amount < 0) 956: { 957: vpos = xp.vpos; 958: pos = xp.bufpos; 959: val.hpos = lmargin; 960: if (pos == NumCharacters + 1) 961: vpos = height + scroll_amount; 962: else if (xp.contin && xp.hpos != lmargin) 963: { 964: val.hpos = xp.prevhpos - width + lmargin; 965: pos--; 966: } 967: 968: blank_end_of_window = 1; 969: tab_offset = pos_tab_offset (w, pos); 970: if (val.hpos < 0) 971: tab_offset += XFASTINT (w->width) - 1; 972: 973: while (vpos < height) 974: { 975: val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset); 976: tab_offset += XFASTINT (w->width) - 1; 977: if (val.vpos) tab_offset = 0; 978: pos = val.bufpos; 979: } 980: 981: /* Here is a case where display_line_text sets point_vpos wrong. 982: Make it be fixed up, below. */ 983: if (xp.bufpos == NumCharacters + 1 984: && xp.bufpos == point) 985: point_vpos = -1; 986: } 987: 988: /* Attempt to adjust end-of-text positions to new bottom line */ 989: if (scroll_amount) 990: { 991: delta = height - xp.vpos; 992: if (delta < 0 993: || (delta > 0 && xp.bufpos <= NumCharacters) 994: || (delta == 0 && xp.hpos)) 995: { 996: val = *vmotion (bf_s1 + bf_s2 + 1 - XFASTINT (w->window_end_pos), 997: delta, width, hscroll, window); 998: XFASTINT (w->window_end_pos) = bf_s1 + bf_s2 + 1 - val.bufpos; 999: XFASTINT (w->window_end_vpos) += val.vpos; 1000: } 1001: } 1002: 1003: /* If point was not in a line that was displayed, find it */ 1004: if (point_vpos < 0) 1005: { 1006: val = *compute_motion (start, 0, lmargin, point, 10000, 10000, 1007: width, hscroll, pos_tab_offset (w, start)); 1008: /* Admit failure if point is off screen now */ 1009: if (val.vpos >= height) 1010: { 1011: for (vpos = 0; vpos < height; vpos++) 1012: cancel_line (vpos + top); 1013: return 0; 1014: } 1015: point_vpos = val.vpos + top; 1016: point_hpos = val.hpos + XFASTINT (w->left); 1017: } 1018: 1019: cursX = max (0, point_hpos); 1020: cursY = point_vpos; 1021: 1022: if (debug_end_pos) 1023: { 1024: val = *compute_motion (start, 0, lmargin, NumCharacters + 1, 1025: height, - (1 << (SHORTBITS - 1)), 1026: width, hscroll, pos_tab_offset (w, start)); 1027: if (val.vpos != XFASTINT (w->window_end_vpos)) 1028: abort (); 1029: if ((XFASTINT (w->window_end_pos) < 0 1030: ? -1 - XFASTINT (w->window_end_pos) 1031: : XFASTINT (w->window_end_pos)) 1032: != bf_s1 + bf_s2 + 1 - val.bufpos) 1033: abort (); 1034: } 1035: 1036: return 1; 1037: } 1038: 1039: /* Display one line of window w, starting at position `start' in w's buffer. 1040: Display starting at horizontal position `hpos', 1041: which is normally zero or negative. 1042: A negative value causes output up to hpos = 0 to be discarded. 1043: This is done for negative hscroll, or when this is a continuation line 1044: and the continuation occurred in the middle of a multi-column character. 1045: 1046: `taboffset' is an offset for ostensible hpos, used in tab stop calculations. 1047: 1048: Display on position `vpos' on the screen. (origin 0). 1049: 1050: Returns a `struct position' giving character to start next line with 1051: and where to display it, including a zero or negative hpos. 1052: The vpos field is not really a vpos; it is 1 unless the line is continued */ 1053: 1054: struct position val_display_text_line; 1055: 1056: struct position * 1057: display_text_line (w, start, vpos, hpos, taboffset) 1058: struct window *w; 1059: int start; 1060: int vpos; 1061: int hpos; 1062: int taboffset; 1063: { 1064: register int pos = start; 1065: register int c; 1066: register char *p1; 1067: int end; 1068: register int pause; 1069: register unsigned char *p; 1070: char *endp; 1071: register char *startp; 1072: register char *p1prev; 1073: register struct display_line *line; 1074: int tab_width = XFASTINT (XBUFFER (w->buffer)->tab_width); 1075: int ctl_arrow = !NULL (XBUFFER (w->buffer)->ctl_arrow); 1076: int width = XFASTINT (w->width) - 1 1077: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width); 1078: struct position val; 1079: int lastpos; 1080: int invis; 1081: int hscroll = XINT (w->hscroll); 1082: int truncate = hscroll 1083: || (truncate_partial_width_windows 1084: && XFASTINT (w->width) < screen_width) 1085: || !NULL (XBUFFER (w->buffer)->truncate_lines); 1086: int selective 1087: = XTYPE (bf_cur->selective_display) == Lisp_Int 1088: ? XINT (bf_cur->selective_display) 1089: : !NULL (bf_cur->selective_display) ? -1 : 0; 1090: 1091: hpos += XFASTINT (w->left); 1092: line = get_display_line (vpos, XFASTINT (w->left)); 1093: if (tab_width <= 0) tab_width = 1; 1094: 1095: if (w == XWINDOW (minibuf_window) && start == 1) 1096: { 1097: if (minibuf_prompt) 1098: hpos = display_string (w, line, minibuf_prompt, hpos, 1099: !truncate ? '\\' : '$', 1100: 0); 1101: minibuf_prompt_width = hpos; 1102: } 1103: 1104: p1 = line->body + hpos; 1105: 1106: end = NumCharacters + 1; 1107: 1108: startp = line->body + XFASTINT (w->left); 1109: endp = startp + width; 1110: 1111: /* Loop generating characters. 1112: Stop at end of buffer, before newline, 1113: or if reach or pass continuation column. */ 1114: 1115: pause = pos; 1116: while (p1 < endp) 1117: { 1118: p1prev = p1; 1119: if (pos == pause) 1120: { 1121: if (pos == end) 1122: break; 1123: if (pos == point && point_vpos < 0) 1124: { 1125: point_vpos = vpos; 1126: point_hpos = p1 - startp; 1127: } 1128: 1129: pause = end; 1130: if (pos < point && point < pause) 1131: pause = point; 1132: if (pos <= bf_s1 && bf_s1 + 1 < pause) 1133: pause = bf_s1 + 1; 1134: 1135: p = &CharAt (pos); 1136: } 1137: c = *p++; 1138: if (c >= 040 && c < 0177) 1139: { 1140: if (p1 >= startp) 1141: *p1 = c; 1142: p1++; 1143: } 1144: else if (c == '\n') 1145: { 1146: invis = 0; 1147: while (pos < end 1148: && selective > 0 1149: && position_indentation (pos + 1) >= selective) 1150: { 1151: invis = 1; 1152: pos = ScanBf ('\n', pos + 1, 1); 1153: if (CharAt (pos - 1) == '\n') 1154: pos--; 1155: } 1156: if (invis) 1157: { 1158: p1 += 4; 1159: if (p1 - startp > width) 1160: p1 = endp; 1161: strncpy (p1prev, " ...", p1 - p1prev); 1162: } 1163: break; 1164: } 1165: else if (c == '\t') 1166: { 1167: do 1168: { 1169: if (p1 >= startp) 1170: *p1 = ' '; 1171: p1++; 1172: } 1173: while ((p1 - startp + taboffset + hscroll - (hscroll > 0)) 1174: % tab_width); 1175: } 1176: else if (c == Ctl('M') && !NULL (bf_cur->selective_display)) 1177: { 1178: pos = ScanBf ('\n', pos, 1); 1179: if (CharAt (pos - 1) == '\n') 1180: pos--; 1181: break; 1182: } 1183: else if (c < 0200 && ctl_arrow) 1184: { 1185: if (p1 >= startp) 1186: *p1 = '^'; 1187: p1++; 1188: if (p1 >= startp) 1189: *p1 = c ^ 0100; 1190: p1++; 1191: } 1192: else 1193: { 1194: if (p1 >= startp) 1195: *p1 = '\\'; 1196: p1++; 1197: if (p1 >= startp) 1198: *p1 = (c >> 6) + '0'; 1199: p1++; 1200: if (p1 >= startp) 1201: *p1 = (7 & (c >> 3)) + '0'; 1202: p1++; 1203: if (p1 >= startp) 1204: *p1 = (7 & c) + '0'; 1205: p1++; 1206: } 1207: pos++; 1208: } 1209: 1210: val.hpos = - XINT (w->hscroll); 1211: if (val.hpos) 1212: { 1213: val.hpos++; 1214: /* If line not empty, insert truncation-at-left marker */ 1215: if (pos != start) 1216: { 1217: *startp = '$'; 1218: if (p1 <= startp) 1219: p1 = startp + 1; 1220: if (line->length <= XFASTINT (w->left)) 1221: line->length = XFASTINT (w->left) + 1; 1222: } 1223: } 1224: val.vpos = 1; 1225: 1226: /* Handle continuation in middle of a character */ 1227: /* by backing up over it */ 1228: if (p1 > endp) 1229: { 1230: /* Start the next line with that same character */ 1231: pos--; 1232: /* but at a negative hpos, to skip the columns output on this line. */ 1233: val.hpos += p1prev - endp; 1234: /* Keep in this line everything up to the continuation column. */ 1235: p1 = endp; 1236: } 1237: 1238: /* Finish deciding which character to start the next line on, 1239: and what hpos to start it at. 1240: Also set `lastpos' to the last position which counts as "on this line" 1241: for cursor-positioning. */ 1242: 1243: lastpos = pos; 1244: 1245: if (pos < NumCharacters + 1) 1246: { 1247: if (CharAt (pos) == '\n') 1248: /* If stopped due to a newline, start next line after it */ 1249: pos++; 1250: else 1251: /* Stopped due to right margin of window */ 1252: { 1253: if (truncate) 1254: { 1255: *p1++ = '$'; 1256: /* Truncating => start next line after next newline, 1257: and point is on this line if it is before the newline, 1258: and skip none of first char of next line */ 1259: pos = ScanBf ('\n', pos, 1); 1260: val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0; 1261: 1262: lastpos = pos - (CharAt (pos - 1) == '\n'); 1263: } 1264: else 1265: { 1266: *p1++ = '\\'; 1267: val.vpos = 0; 1268: lastpos = 0; 1269: } 1270: } 1271: } 1272: 1273: if (start <= point && point <= lastpos && point_vpos < 0) 1274: { 1275: point_vpos = vpos; 1276: point_hpos = p1 - startp; 1277: } 1278: 1279: if (point_vpos == vpos) 1280: { 1281: if (point_hpos < 0) point_hpos = 0; 1282: if (point_hpos > width) point_hpos = width; 1283: point_hpos += XFASTINT (w->left); 1284: if (w == XWINDOW (selected_window)) 1285: { 1286: cursY = point_vpos; 1287: cursX = point_hpos; 1288: 1289: /* Line is not continued and did not start in middle of character */ 1290: if (hpos == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0) 1291: && val.vpos) 1292: { 1293: this_line_bufpos = start; 1294: this_line_buffer = bf_cur; 1295: this_line_vpos = vpos; 1296: this_line_hpos = hpos; 1297: this_line_endpos = bf_s1 + bf_s2 + 1 - lastpos; 1298: } 1299: else 1300: this_line_bufpos = 0; 1301: } 1302: } 1303: 1304: if (XFASTINT (w->width) + XFASTINT (w->left) != screen_width) 1305: { 1306: endp++; 1307: if (p1 < startp) p1 = startp; 1308: while (p1 < endp) *p1++ = ' '; 1309: *p1++ = '|'; 1310: } 1311: line->length = max (line->length, p1 - line->body); 1312: line->body[line->length] = 0; 1313: 1314: val.bufpos = pos; 1315: val_display_text_line = val; 1316: return &val_display_text_line; 1317: } 1318: 1319: /* Display the mode line for window w */ 1320: 1321: display_mode_line (w) 1322: struct window *w; 1323: { 1324: int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1; 1325: struct display_line *line = get_display_line (vpos, XFASTINT (w->left)); 1326: 1327: register unsigned char *s = XSTRING (bf_cur->mode_line_format)->data; 1328: 1329: display_string (w, line, s, XFASTINT (w->left), 0, 1); 1330: /* Make the mode line inverse video if the entire line 1331: is made of mode lines. 1332: I.e. if this window is full width, 1333: or if it is the child of a full width window 1334: (which implies that that window is split side-by-side 1335: and the rest of this line is mode lines of the sibling windows). */ 1336: if (XFASTINT (w->width) == screen_width 1337: || XFASTINT (XWINDOW (w->parent)->width) == screen_width) 1338: line->highlighted = mode_line_inverse_video; 1339: } 1340: 1341: char fmodetrunc_buf[100]; 1342: 1343: char * 1344: fmodetrunc (str, width) 1345: char *str; 1346: long width; 1347: { 1348: register char *buf = fmodetrunc_buf; 1349: register char *bp = buf; 1350: register long len; 1351: 1352: len = strlen(str); 1353: if (width && width < len) 1354: { 1355: strcpy(buf,str+len-width); 1356: if (buf[0] != '/') 1357: while (*bp) 1358: if (*bp++ == '/') 1359: { 1360: bp--; 1361: *--bp = '$'; 1362: return bp; 1363: } 1364: buf[0] = '$'; 1365: return buf; 1366: } 1367: return str; 1368: } 1369: 1370: char decode_mode_spec_buf[MScreenWidth + 1]; 1371: 1372: char * 1373: decode_mode_spec (w, string, data_ptr, len_ptr, max_ptr) 1374: struct window *w; 1375: register char *string; 1376: char **data_ptr; 1377: int *len_ptr; 1378: int *max_ptr; 1379: { 1380: register int width = 0; 1381: register char c; 1382: Lisp_Object lstr, proc, list; 1383: register char *str; 1384: int len; 1385: int pos, total; 1386: char *tbuf = decode_mode_spec_buf; 1387: #define tbufsize (sizeof decode_mode_spec_buf) 1388: 1389: lstr = Qnil, str = 0; 1390: 1391: while (isdigit (c = *string++)) 1392: width = width * 10 + (c - '0'); 1393: 1394: switch (c) 1395: { 1396: case 'b': 1397: lstr = bf_cur->name; 1398: if (width && XSTRING (lstr)->size > width) 1399: width = min (2 * width, XSTRING (lstr)->size); 1400: if (width && XSTRING (lstr)->size > width) 1401: { 1402: str = (char *) alloca (width + 1); 1403: bcopy (XSTRING (lstr)->data, str, width - 3); 1404: bcopy ("...", str + width - 3, 4); 1405: lstr = Qnil; 1406: } 1407: break; 1408: 1409: case 'f': 1410: if (NULL (bf_cur->filename)) 1411: str = "[none]"; 1412: else if (XTYPE (bf_cur->filename) == Lisp_String) 1413: str = fmodetrunc (XSTRING (bf_cur -> filename)->data, width); 1414: break; 1415: 1416: case 'm': 1417: lstr = bf_cur->mode_name; 1418: total = min (XSTRING (lstr)->size, tbufsize - 30); 1419: if (total < 0) total = 0; 1420: bcopy (XSTRING (lstr)->data, tbuf, total); 1421: len = 0; 1422: list = bf_cur->minor_modes; 1423: while (1) 1424: { 1425: if (!LISTP (list) && !len) 1426: { 1427: list = Vglobal_minor_modes; 1428: len = 1; 1429: } 1430: 1431: if (!(total < tbufsize - 30 && LISTP (list))) 1432: break; 1433: 1434: lstr = XCONS (list)->car; 1435: if (!LISTP (lstr)) 1436: goto foo; 1437: lstr = XCONS (lstr)->cdr; 1438: if (XTYPE (lstr) != Lisp_String) 1439: goto foo; 1440: tbuf[total++] = ' '; 1441: pos = min (XSTRING (lstr)->size, tbufsize - 30 - total); 1442: if (pos < 0) 1443: pos = 0; 1444: bcopy (XSTRING (lstr)->data, tbuf + total, pos); 1445: total += pos; 1446: foo: 1447: list = Fcdr (list); 1448: } 1449: str = tbuf; 1450: tbuf[total] = 0; 1451: /* if (bf_cur->abbrev_mode) 1452: strcat (tbuf, " Abbrev"); */ 1453: if (bf_head_clip > 1 || bf_tail_clip > 0) 1454: strcat (tbuf, " Narrow"); 1455: if (defining_kbd_macro) 1456: strcat (tbuf, " Def"); 1457: lstr = Qnil; 1458: break; 1459: 1460: case 'M': 1461: lstr = Vglobal_mode_string; 1462: break; 1463: 1464: case '*': 1465: str = !NULL (bf_cur->read_only) ? "%" 1466: : bf_modified > bf_cur->save_modified ? "*" :"-"; 1467: break; 1468: 1469: case 's': 1470: /* status of process */ 1471: #ifdef subprocesses 1472: proc = Fget_buffer_process (Fcurrent_buffer ()); 1473: if (NULL (proc)) 1474: str = "no process"; 1475: else 1476: lstr = Fsymbol_name (Fprocess_status (proc)); 1477: #else 1478: str = "no process"; 1479: #endif /* subprocesses */ 1480: break; 1481: 1482: case 'p': 1483: pos = marker_position (w->start); 1484: total = NumCharacters + 1 - FirstCharacter; 1485: 1486: if ((XFASTINT (w->window_end_pos) < 0 1487: ? -1 - XFASTINT (w->window_end_pos) 1488: : XFASTINT (w->window_end_pos)) 1489: <= bf_tail_clip) 1490: { 1491: if (pos <= FirstCharacter) 1492: str = "All"; 1493: else 1494: str = "Bottom"; 1495: } 1496: else if (pos <= FirstCharacter) 1497: str = "Top"; 1498: else 1499: { 1500: total = ((pos - FirstCharacter) * 100 + total - 1) / total; 1501: /* We can't normally display a 3-digit number, 1502: so get us a 2-digit number that is close. */ 1503: if (total == 100) 1504: total = 99; 1505: sprintf (tbuf, "%2d%%", total); 1506: str = tbuf; 1507: } 1508: break; 1509: 1510: case '[': 1511: str = "[[[[[[[[[[" + 10 - (RecurseDepth - MinibufDepth); 1512: if (RecurseDepth - MinibufDepth > 10) 1513: str = "[[[... "; 1514: break; 1515: 1516: case ']': 1517: str = "]]]]]]]]]]" + 10 - (RecurseDepth - MinibufDepth); 1518: if (RecurseDepth - MinibufDepth > 10) 1519: str = " ...]]]"; 1520: break; 1521: 1522: case '-': 1523: str = "--------------------------------------------------------------------------------------------------------------------------------------------"; 1524: } 1525: 1526: /* Report the chosen mode item to the caller */ 1527: 1528: if (str) 1529: *data_ptr = str, *len_ptr = strlen (str); 1530: else if (XTYPE (lstr) == Lisp_String) 1531: *data_ptr = (char *) XSTRING (lstr)->data, 1532: *len_ptr = XSTRING (lstr)->size; 1533: else 1534: *data_ptr = 0, *len_ptr = 0; 1535: 1536: /* Report specified truncation or padding */ 1537: 1538: *max_ptr = width; 1539: 1540: /* Tell caller how much of mode line format was used up */ 1541: 1542: return string; 1543: } 1544: 1545: /* Display `string' on one line of window `w', starting at `hpos'. 1546: Display on the display_line `line', which should have 1547: been obtained by get_display_line (vpos, hpos) 1548: or in some suitable manner. 1549: 1550: `truncate' is character to display at end if truncated. 1551: `modeline' nonzero means substitute for % constructs. 1552: 1553: Returns ending hpos */ 1554: 1555: 1556: display_string (w, line, string, hpos, truncate, modeline) 1557: struct window *w; 1558: register struct display_line *line; 1559: unsigned char *string; 1560: int hpos; 1561: int truncate; 1562: int modeline; 1563: { 1564: register int c; 1565: register unsigned char *p1; 1566: int width = XFASTINT (w->width) - 1 1567: - (XFASTINT (w->width) + XFASTINT (w->left) != screen_width); 1568: int hscroll = XINT (w->hscroll); 1569: int tab_width = 8; 1570: register unsigned char *start; 1571: register unsigned char *end; 1572: char *modeeltstring; 1573: int modeeltleft = 0; 1574: int modeeltmax = 0; 1575: 1576: p1 = (unsigned char *) line->body + hpos; 1577: start = (unsigned char *) line->body + XFASTINT (w->left); 1578: end = start + width; 1579: 1580: while (p1 < end) 1581: { 1582: if (modeeltmax) 1583: { 1584: modeeltmax--; 1585: if (modeeltleft-- > 0) 1586: c = *modeeltstring++; 1587: else 1588: c = ' '; 1589: } 1590: else 1591: { 1592: c = *string++; 1593: if (!c) break; 1594: if (c == '%' && modeline) 1595: { 1596: string = (unsigned char *) 1597: decode_mode_spec (w, string, &modeeltstring, 1598: &modeeltleft, &modeeltmax); 1599: 1600: if (!modeeltmax) 1601: modeeltmax = modeeltleft; 1602: else if (modeeltleft > modeeltmax) 1603: modeeltleft = modeeltmax; 1604: 1605: continue; 1606: } 1607: } 1608: 1609: if (c >= 040 && c < 0177) 1610: { 1611: if (p1 >= start) 1612: *p1 = c; 1613: p1++; 1614: } 1615: else if (c == '\t') 1616: { 1617: do 1618: { 1619: if (p1 >= start) 1620: *p1 = ' '; 1621: p1++; 1622: } 1623: while ((p1 - start + hscroll - (hscroll > 0)) % tab_width); 1624: } 1625: else if (c < 0200 && default_ctl_arrow) 1626: { 1627: if (p1 >= start) 1628: *p1 = '^'; 1629: p1++; 1630: if (p1 >= start) 1631: *p1 = c ^ 0100; 1632: p1++; 1633: } 1634: else 1635: { 1636: if (p1 >= start) 1637: *p1 = '\\'; 1638: p1++; 1639: if (p1 >= start) 1640: *p1 = (c >> 6) + '0'; 1641: p1++; 1642: if (p1 >= start) 1643: *p1 = (7 & (c >> 3)) + '0'; 1644: p1++; 1645: if (p1 >= start) 1646: *p1 = (7 & c) + '0'; 1647: p1++; 1648: } 1649: } 1650: 1651: if (c) 1652: { 1653: p1 = end; 1654: if (truncate) *p1++ = truncate; 1655: } 1656: 1657: line->length = max (line->length, p1 - (unsigned char *) line->body); 1658: line->body[line->length] = 0; 1659: return p1 - (unsigned char *) line->body; 1660: } 1661: 1662: syms_of_xdisp () 1663: { 1664: DefLispVar ("global-mode-string", &Vglobal_mode_string, 1665: "String which mode line can display (if its format requests to)."); 1666: Vglobal_mode_string = Qnil; 1667: 1668: DefLispVar ("global-minor-modes", &Vglobal_minor_modes, 1669: "Alist of minor modes that are not per buffer.\n\ 1670: Cdr of each element is a string to display in mode line."); 1671: 1672: DefIntVar ("scroll-step", &scroll_step, 1673: "*The number of lines to try scrolling a window by when point moves out.\n\ 1674: If that fails to bring point back on screen, point is centered instead.\n\ 1675: If this is zero, point is always centered after it moves off screen."); 1676: 1677: DefIntVar ("debug-end-pos", &debug_end_pos, "Don't ask"); 1678: 1679: DefBoolVar ("truncate-partial-width-windows", 1680: &truncate_partial_width_windows, 1681: "*Non-nil means truncate lines in all windows less than full screen wide."); 1682: truncate_partial_width_windows = 1; 1683: 1684: DefBoolVar ("mode-line-inverse-video", &mode_line_inverse_video, 1685: "*Non-nil means use inverse video, or other suitable display mode, for the mode line."); 1686: mode_line_inverse_video = 1; 1687: 1688: defsubr (&Sredraw_display); 1689: } 1690: 1691: /* initialize the window system */ 1692: init_xdisp () 1693: { 1694: Lisp_Object root_window; 1695: #ifndef COMPILER_REGISTER_BUG 1696: register 1697: #endif COMPILER_REGISTER_BUG 1698: struct window *mini_w; 1699: 1700: this_line_bufpos = 0; 1701: 1702: mini_w = XWINDOW (minibuf_window); 1703: root_window = mini_w->prev; 1704: 1705: minibuf_message = 0; 1706: prev_minibuf_message = 0; 1707: 1708: if (!noninteractive) 1709: { 1710: XFASTINT (XWINDOW (root_window)->top) = 0; 1711: set_window_height (root_window, screen_height - 1, 0); 1712: XFASTINT (mini_w->top) = screen_height - 1; 1713: set_window_height (minibuf_window, 1, 0); 1714: 1715: XFASTINT (XWINDOW (root_window)->width) = screen_width; 1716: XFASTINT (mini_w->width) = screen_width; 1717: } 1718: }