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

Defined functions

DEFUN defined in line 151; never used
decode_mode_spec defined in line 1372; used 1 times
display_minibuf_message defined in line 212; used 3 times
display_mode_line defined in line 1321; used 1 times
display_string defined in line 1556; used 3 times
display_text_line defined in line 1056; used 5 times
fmodetrunc defined in line 1343; used 1 times
init_xdisp defined in line 1692; used 1 times
mark_window_display_accurate defined in line 419; used 4 times
redisplay_all_windows defined in line 452; used 1 times
redisplay_window defined in line 466; used 2 times
redisplay_windows defined in line 459; used 3 times
syms_of_xdisp defined in line 1662; used 1 times
try_window defined in line 684; used 4 times
try_window_id defined in line 736; used 1 times

Defined variables

MinibufDepth defined in line 123; used 10 times
RecurseDepth defined in line 121; used 8 times
Vglobal_minor_modes defined in line 80; used 2 times
Vglobal_mode_string defined in line 78; used 3 times
beg_unchanged defined in line 131; used 14 times
blank_end_of_window defined in line 89; used 4 times
buffer_shared defined in line 92; used 4 times
clip_changed defined in line 145; used 10 times
debug_end_pos defined in line 101; used 2 times
decode_mode_spec_buf defined in line 1370; used 2 times
do_id defined in line 444; used 1 times
end_unchanged defined in line 136; used 14 times
fmodetrunc_buf defined in line 1341; used 1 times
message_buf defined in line 169; used 3 times
minibuf_message defined in line 116; used 18 times
minibuf_prompt defined in line 110; used 4 times
mode_line_inverse_video defined in line 106; used 3 times
noninteractive_need_newline defined in line 39; used 4 times
point_hpos defined in line 99; used 12 times
point_vpos defined in line 98; used 16 times
prev_minibuf_message defined in line 72; used 3 times
scroll_step defined in line 85; used 5 times
this_line_buffer defined in line 66; used 2 times
this_line_bufpos defined in line 52; used 8 times
this_line_endpos defined in line 56; used 3 times
this_line_hpos defined in line 63; used 2 times
this_line_vpos defined in line 59; used 3 times
truncate_partial_width_windows defined in line 76; used 3 times
unchanged_modified defined in line 141; used 2 times
val_display_text_line defined in line 1054; used 2 times
windows_or_buffers_changed defined in line 149; used 8 times

Defined macros

CURRENT_END_POS defined in line 44; used 1 times
max defined in line 42; used 9 times
min defined in line 41; used 3 times
tbufsize defined in line 1387; used 3 times
Last modified: 1986-03-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3810
Valid CSS Valid XHTML 1.0 Strict