1: /* Window creation, deletion and examination for GNU Emacs.
   2:    Does not include redisplay.
   3:    Copyright (C) 1985 Richard M. Stallman.
   4: 
   5: This file is part of GNU Emacs.
   6: 
   7: GNU Emacs is distributed in the hope that it will be useful,
   8: but WITHOUT ANY WARRANTY.  No author or distributor
   9: accepts responsibility to anyone for the consequences of using it
  10: or for whether it serves any particular purpose or works at all,
  11: unless he says so in writing.  Refer to the GNU Emacs General Public
  12: License for full details.
  13: 
  14: Everyone is granted permission to copy, modify and redistribute
  15: GNU Emacs, but only under the conditions described in the
  16: GNU Emacs General Public License.   A copy of this license is
  17: supposed to have been given to you along with GNU Emacs so you
  18: can know your rights and responsibilities.  It should be in a
  19: file named COPYING.  Among other things, the copyright notice
  20: and this notice must be preserved on all copies.  */
  21: 
  22: 
  23: #include "config.h"
  24: #include "lisp.h"
  25: #include "buffer.h"
  26: #include "window.h"
  27: #include "commands.h"
  28: #include "indent.h"
  29: #include "termchar.h"
  30: 
  31: Lisp_Object Qwindowp;
  32: 
  33: Lisp_Object Fnext_window (), Fdelete_window (), Fselect_window ();
  34: Lisp_Object Fshow_buffer (), Fsplit_window (), Frecenter ();
  35: 
  36: /* This is the window which displays the minibuffer.
  37: It is always the same window.  */
  38: 
  39: Lisp_Object minibuf_window;
  40: 
  41: /* This is the window in which the terminal's cursor should
  42:  be left when nothing is being done with it.  This must
  43:  always be a leaf window, and its buffer is selected by
  44:  the top level editing loop at the end of each command.  */
  45: 
  46: Lisp_Object selected_window;
  47: 
  48: /* If a window gets smaller than either of these, it is removed. */
  49: 
  50: int window_min_height;
  51: int window_min_width;
  52: 
  53: /* Nonzero implies pop_to_buffer should create windows. */
  54: 
  55: int pop_up_windows;
  56: 
  57: /* display-buffer always splits the largest window
  58:  if that window is more than this high */
  59: 
  60: int split_height_threshold;
  61: 
  62: /* Number of lines of continuity in scrolling by screenfuls.  */
  63: 
  64: int next_screen_context_lines;
  65: 
  66: /* Incremented for each window created.  */
  67: 
  68: static int sequence_number;
  69: 
  70: DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
  71:   "Returns t if OBJ is a window.")
  72:   (obj)
  73:      Lisp_Object obj;
  74: {
  75:   return XTYPE (obj) == Lisp_Window ? Qt : Qnil;
  76: }
  77: 
  78: Lisp_Object
  79: make_window ()
  80: {
  81:   Lisp_Object val;
  82:   register struct window *p;
  83: 
  84:   val = Fmake_vector (
  85:     make_number ((sizeof (struct window) - sizeof (struct Lisp_Vector))
  86:          / sizeof (Lisp_Object)),
  87:     Qnil);
  88:   XSETTYPE (val, Lisp_Window);
  89:   p = XWINDOW (val);
  90:   XFASTINT (p->left) = XFASTINT (p->top)
  91:     = XFASTINT (p->height) = XFASTINT (p->width)
  92:       = XFASTINT (p->hscroll) = 0;
  93:   XFASTINT (p->last_point_x) = XFASTINT (p->last_point_y) = 0;
  94:   p->start = Fmake_marker ();
  95:   p->pointm = Fmake_marker ();
  96:   XFASTINT (p->sequence_number) = ++sequence_number;
  97:   XFASTINT (p->use_time) = 0;
  98:   return val;
  99: }
 100: 
 101: DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
 102:   "Return the window that the cursor appears in and commands apply to.")
 103:   ()
 104: {
 105:   return selected_window;
 106: }
 107: 
 108: DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
 109:   Spos_visible_in_window_p, 0, 2, 0,
 110:   "Return t if position POS is currently on the screen in WINDOW.\n\
 111: Returns nil if that position is scrolled vertically out of view.\n\
 112: POS defaults to point; WINDOW, to the selected window.")
 113:   (pos, window)
 114:      Lisp_Object pos, window;
 115: {
 116:   register struct window *w;
 117:   register int top;
 118:   register int height;
 119:   register int posint;
 120:   register struct buffer_text *text;
 121:   struct position posval;
 122: 
 123:   if (NULL (pos))
 124:     posint = point;
 125:   else
 126:     {
 127:       CHECK_NUMBER_COERCE_MARKER (pos, 0);
 128:       posint = XINT (pos);
 129:     }
 130: 
 131:   if (NULL (window))
 132:     window = selected_window;
 133:   else
 134:     CHECK_WINDOW (window, 1);
 135:   w = XWINDOW (window);
 136:   top = marker_position (w->start);
 137: 
 138:   if (posint < top)
 139:     return Qnil;
 140: 
 141:   height = XFASTINT (w->height) - !EQ (window, minibuf_window);
 142: 
 143:   bf_cur->text = bf_text;
 144:   text = &XBUFFER (w->buffer)->text;
 145:   if (XFASTINT (w->last_modified) >= text->modified)
 146:     {
 147:       /* If screen is up to date,
 148: 	 use the info recorded about how much text fit on it. */
 149:       if (posint < text->size1 + text->size2 + 1 - XFASTINT (w->window_end_pos)
 150:       || (XFASTINT (w->window_end_vpos) < height))
 151:     return Qt;
 152:       return Qnil;
 153:     }
 154:   else
 155:     {
 156:       if (posint > text->size1 + text->size2 + 1)
 157:     return Qnil;
 158:       /* If that info is not correct, calculate afresh */
 159:       posval = *compute_motion (top, 0, 0,
 160:                    posint, height, 0,
 161:                    XFASTINT (w->width) - 1
 162:                    - (XFASTINT (w->width) + XFASTINT (w->left) != XFASTINT (XWINDOW (minibuf_window)->width)),
 163: 
 164:                    XINT (w->hscroll), 0);
 165:       return posval.vpos < height ? Qt : Qnil;
 166:     }
 167: }
 168: 
 169: struct window *
 170: decode_window (window)
 171:      Lisp_Object window;
 172: {
 173:   if (NULL (window))
 174:     return XWINDOW (selected_window);
 175: 
 176:   CHECK_WINDOW (window, 0);
 177:   return XWINDOW (window);
 178: }
 179: 
 180: DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
 181:   "Return the buffer that WINDOW is displaying.")
 182:   (window)
 183:      Lisp_Object window;
 184: {
 185:   return decode_window (window)->buffer;
 186: }
 187: 
 188: DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
 189:   "Return the number of lines in WINDOW (including its mode line).")
 190:   (window)
 191:      Lisp_Object window;
 192: {
 193:   return decode_window (window)->height;
 194: }
 195: 
 196: DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
 197:   "Return the number of columns in WINDOW.")
 198:   (window)
 199:      Lisp_Object window;
 200: {
 201:   return decode_window (window)->width;
 202: }
 203: 
 204: DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
 205:   "Return the number of columns by which WINDOW is scrolled from left margin.")
 206:   (window)
 207:      Lisp_Object window;
 208: {
 209:   return decode_window (window)->hscroll;
 210: }
 211: 
 212: DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
 213:   "Set number of columns WINDOW is scrolled from left margin to NCOL.\n\
 214: NCOL should be zero or positive.")
 215:   (window, ncol)
 216:      Lisp_Object window, ncol;
 217: {
 218:   CHECK_NUMBER (ncol, 1);
 219:   if (XINT (ncol) < 0) XFASTINT (ncol) = 0;
 220:   if (XFASTINT (ncol) >= (1 << (SHORTBITS - 1)))
 221:     args_out_of_range (ncol, Qnil);
 222: 
 223:   clip_changed = 1;     /* Prevent redisplay shortcuts */
 224:   decode_window (window)->hscroll = ncol;
 225:   return ncol;
 226: }
 227: 
 228: DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
 229:   "Return a list of the edge coordinates of WINDOW.\n\
 230: \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of screen.")
 231:   (window)
 232:      Lisp_Object window;
 233: {
 234:   register struct window *w = decode_window (window);
 235: 
 236:   return Fcons (w->left, Fcons (w->top,
 237:            Fcons (make_number (XFASTINT (w->left) + XFASTINT (w->width)),
 238:           Fcons (make_number (XFASTINT (w->top)
 239:                       + XFASTINT (w->height)),
 240:              Qnil))));
 241: }
 242: 
 243: DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
 244:   "Return current value of point in WINDOW.")
 245:   (window)
 246:      Lisp_Object window;
 247: {
 248:   return Fmarker_position (decode_window (window)->pointm);
 249: }
 250: 
 251: DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
 252:   "Return position at which display currently starts in WINDOW.")
 253:   (window)
 254:      Lisp_Object window;
 255: {
 256:   return Fmarker_position (decode_window (window)->start);
 257: }
 258: 
 259: DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
 260:   "Make point value in WINDOW be at position POS in WINDOW's buffer.")
 261:   (window, pos)
 262:      Lisp_Object window, pos;
 263: {
 264:   struct window *w = decode_window (window);
 265:   CHECK_NUMBER_COERCE_MARKER (pos, 1);
 266:   Fset_marker (w->pointm, pos, w->buffer);
 267:   return pos;
 268: }
 269: 
 270: DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
 271:   "Make display in WINDOW start at position POS in WINDOW's buffer.\n\
 272: Optional third arg NOFORCE non-nil inhibits next redisplay\n\
 273: from overriding motion of point in order to display at this exact start.")
 274:   (window, pos, noforce)
 275:      Lisp_Object window, pos, noforce;
 276: {
 277:   struct window *w = decode_window (window);
 278:   CHECK_NUMBER_COERCE_MARKER (pos, 1);
 279:   Fset_marker (w->start, pos, w->buffer);
 280:   if (NULL (noforce))
 281:     w->force_start = Qt;
 282:   w->redo_mode_line = Qt;
 283:   XFASTINT (w->last_modified) = 0;
 284:   return pos;
 285: }
 286: 
 287: DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
 288:   "Remove WINDOW from the display.  Default is selected window.")
 289:   (window)
 290:      Lisp_Object window;
 291: {
 292:   int osize;
 293:   Lisp_Object tem, parent;
 294:   register struct window *p;
 295: 
 296:   if (NULL (window))
 297:     window = selected_window;
 298:   else
 299:     CHECK_WINDOW (window, 0);
 300: 
 301:   p = XWINDOW (window);
 302:   parent = p->parent;
 303:   if (NULL (parent))
 304:     error ("Attempt to delete minibuffer or sole ordinary window");
 305: 
 306:   windows_or_buffers_changed++;
 307: 
 308:   if (EQ (window, selected_window))
 309:     Fselect_window (Fnext_window (window, Qnil));
 310: 
 311:   tem = p->buffer;
 312:   /* tem is null for dummy parent windows
 313:      (which have inferiors but not any contents themselves) */
 314:   if (!NULL (tem))
 315:     {
 316:       unshow_buffer (p);
 317:       unchain_marker (p->pointm);
 318:       unchain_marker (p->start);
 319:     }
 320: 
 321:   tem = p->next;
 322:   if (!NULL (tem))
 323:     XWINDOW (tem)->prev = p->prev;
 324: 
 325:   tem = p->prev;
 326:   if (!NULL (tem))
 327:     XWINDOW (tem)->next = p->next;
 328: 
 329:   if (EQ (window, XWINDOW (parent)->hchild))
 330:     XWINDOW (parent)->hchild = p->next;
 331:   if (EQ (window, XWINDOW (parent)->vchild))
 332:     XWINDOW (parent)->vchild = p->next;
 333: 
 334:   /* Stretch the siblings to use all the available space */
 335:   if (!NULL (XWINDOW (parent)->vchild))
 336:     {
 337:       /* It's a vertical combination */
 338:       osize = XFASTINT (XWINDOW (parent)->height);
 339:       XFASTINT (XWINDOW (parent)->height)
 340:     -= XFASTINT (p->height);
 341:       set_window_height (parent, osize, 1);
 342:     }
 343:   if (!NULL (XWINDOW (parent)->hchild))
 344:     {
 345:       /* It's a horizontal combination */
 346:       osize = XFASTINT (XWINDOW (parent)->width);
 347:       XFASTINT (XWINDOW (parent)->width)
 348:     -= XFASTINT (p->width);
 349:       set_window_width (parent, osize, 1);
 350:     }
 351: 
 352:   /* If parent now has only one child,
 353:      put the child into the parent's place.  */
 354: 
 355:   tem = XWINDOW (parent)->hchild;
 356:   if (NULL (tem))
 357:     tem = XWINDOW (parent)->vchild;
 358:   if (NULL (XWINDOW (tem)->next))
 359:     replace_window (parent, tem);
 360:   return Qnil;
 361: }
 362: 
 363: /* Put replacement into the window structure in place of old. */
 364: 
 365: replace_window (old, replacement)
 366:      Lisp_Object old, replacement;
 367: {
 368:   Lisp_Object tem;
 369:   register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
 370: 
 371:   p->left = o->left;
 372:   p->top = o->top;
 373:   p->width = o->width;
 374:   p->height = o->height;
 375: 
 376:   p->next = tem = o->next;
 377:   if (!NULL (tem))
 378:     XWINDOW (tem)->prev = replacement;
 379: 
 380:   p->prev = tem = o->prev;
 381:   if (!NULL (tem))
 382:     XWINDOW (tem)->next = replacement;
 383: 
 384:   p->parent = tem = o->parent;
 385:   if (!NULL (tem))
 386:     {
 387:       if (EQ (XWINDOW (tem)->vchild, old))
 388:     XWINDOW (tem)->vchild = replacement;
 389:       if (EQ (XWINDOW (tem)->hchild, old))
 390:     XWINDOW (tem)->hchild = replacement;
 391:     }
 392: 
 393: /*** Here, if replacement is a vertical combination
 394: and so is its new parent, we should make replacement's
 395: children be children of that parent instead.  ***/
 396: }
 397: 
 398: DEFUN ("next-window", Fnext_window, Snext_window, 0, 2, 0,
 399:   "Return next window after WINDOW in canonical ordering of windows.")
 400:   (window, yesmini)
 401:      Lisp_Object window, yesmini;
 402: {
 403:   Lisp_Object tem;
 404:   if (NULL (window))
 405:     window = selected_window;
 406:   else
 407:     CHECK_WINDOW (window, 0);
 408:   do
 409:     {
 410:       while (tem = XWINDOW (window)->next, NULL (tem))
 411:     if (tem = XWINDOW (window)->parent, !NULL (tem))
 412:       window = tem;
 413:         else  /* window must be minibuf_window now */
 414:       {
 415:         tem = XWINDOW (window)->prev;
 416:         break;
 417:       }
 418:       window = tem;
 419:       while (1)
 420:     {
 421:       if (!NULL (XWINDOW (window)->hchild))
 422:         window = XWINDOW (window)->hchild;
 423:       else if (!NULL (XWINDOW (window)->vchild))
 424:         window = XWINDOW (window)->vchild;
 425:       else break;
 426:     }
 427:     }
 428:   while (EQ (window, minibuf_window) && NULL (yesmini) && !MinibufDepth);
 429:   return window;
 430: }
 431: 
 432: DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 1, 0,
 433:   "Return previous window before WINDOW in canonical ordering of windows.")
 434:   (window)
 435:      Lisp_Object window;
 436: {
 437:   Lisp_Object tem;
 438:   if (NULL (window))
 439:     window = selected_window;
 440:   else
 441:     CHECK_WINDOW (window, 0);
 442:   do  /* at least once, and until not the minibuffer */
 443:     {
 444:       while (tem = XWINDOW (window)->prev, NULL (tem))
 445:     if (tem = XWINDOW (window)->parent, !NULL (tem))
 446:       window = tem;
 447:         else  /* window must be the root window now */
 448:       {
 449:         tem = minibuf_window;
 450:         break;
 451:       }
 452:       window = tem;
 453:       while (1)
 454:     {
 455:       if (!NULL (XWINDOW (window)->hchild))
 456:         window = XWINDOW (window)->hchild;
 457:       else if (!NULL (XWINDOW (window)->vchild))
 458:         window = XWINDOW (window)->vchild;
 459:       else break;
 460:       while (tem = XWINDOW (window)->next, !NULL (tem))
 461:         window = tem;
 462:     }
 463:     }
 464:   while (EQ (window, minibuf_window) && !MinibufDepth);
 465:   return window;
 466: }
 467: 
 468: DEFUN ("other-window", Fother_window, Sother_window, 1, 1, "p",
 469:   "Select the ARG'th different window.")
 470:   (n)
 471:      Lisp_Object n;
 472: {
 473:   int i;
 474:   Lisp_Object w;
 475: 
 476:   CHECK_NUMBER (n, 0);
 477:   w = selected_window;
 478:   i = XINT (n);
 479: 
 480:   while (i > 0)
 481:     {
 482:       w = Fnext_window (w, Qnil);
 483:       i--;
 484:     }
 485:   while (i < 0)
 486:     {
 487:       w = Fprevious_window (w);
 488:       i++;
 489:     }
 490:   Fselect_window (w);
 491:   return Qnil;
 492: }
 493: 
 494: Lisp_Object
 495: window_loop (type, obj)
 496:      int type;
 497:      Lisp_Object obj;
 498: {
 499:   Lisp_Object w, w1, ret_w, tem;
 500:   register struct window *p, *q;
 501: 
 502:   w = minibuf_window;
 503:   ret_w = Qnil;
 504:   while (1)
 505:     {
 506:       p = XWINDOW (w);
 507:       w1 = Fnext_window (w, Qt);
 508:       if (!EQ (w, minibuf_window))
 509:     switch (type)
 510:       {
 511:       case 1:
 512:         if (XBUFFER (p->buffer) == XBUFFER (obj))
 513:           return w;
 514:         break;
 515: 
 516:       case 2:
 517:         /* t as arg means consider only full-width windows */
 518:         if (!NULL (obj) && XFASTINT (p->width) != screen_width)
 519:           break;
 520:         if (NULL (ret_w) ||
 521:         XFASTINT (XWINDOW (ret_w)->use_time) > XFASTINT (p->use_time))
 522:           ret_w = w;
 523:         break;
 524: 
 525:       case 3:
 526:         if (p != XWINDOW (obj))
 527:           Fdelete_window (w);
 528:         break;
 529: 
 530:       case 4:
 531:         if (EQ (p->buffer, obj))
 532:           {
 533:         if (NULL (p->parent))
 534:           {
 535:             tem = Fother_buffer (obj);
 536:             if (NULL (tem))
 537:               tem = Fget_buffer_create (build_string ("*scratch*"));
 538:             Fshow_buffer (w, tem);
 539:             Fset_buffer (p->buffer);
 540:           }
 541:         else
 542:           Fdelete_window (w);
 543:           }
 544:         break;
 545: 
 546:       case 5:
 547:         q = XWINDOW (ret_w);
 548:         if (NULL (ret_w) ||
 549:         (XFASTINT (p->height) * XFASTINT (p->width))
 550:         >
 551:         (XFASTINT (q->height) * XFASTINT (q->width)))
 552:           ret_w = w;
 553:         break;
 554: 
 555:       case 6:
 556:         if (EQ (p->buffer, obj))
 557:           {
 558:         tem = Fother_buffer (obj);
 559:         if (NULL (tem))
 560:           tem = Fget_buffer_create (build_string ("*scratch*"));
 561:         Fshow_buffer (w, tem);
 562:         Fset_buffer (p->buffer);
 563:           }
 564:         break;
 565:       }
 566:       w = w1;
 567:       if (EQ (w, minibuf_window))
 568:     return ret_w;
 569:     }
 570: }
 571: 
 572: DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 0, 0,
 573:   "Return the window least recently selected or used for display.")
 574:   ()
 575: {
 576:   Lisp_Object w;
 577:   /* First try for a window that is full-width */
 578:   w = window_loop (2, Qt);
 579:   if (!NULL (w) && !EQ (w, selected_window))
 580:     return w;
 581:   /* If none of them, try the rest */
 582:   return window_loop (2, Qnil);
 583: }
 584: 
 585: DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 0, 0,
 586:   "Return the largest window in area.")
 587:   ()
 588: {
 589:   return window_loop (5, Qnil);
 590: }
 591: 
 592: DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 1, 0,
 593:   "Return a window currently displaying BUFFER, or nil if none.")
 594:   (buffer)
 595:      Lisp_Object buffer;
 596: {
 597:   buffer = Fget_buffer (buffer);
 598:   if (XTYPE (buffer) == Lisp_Buffer)
 599:     return window_loop (1, buffer);
 600:   else return Qnil;
 601: }
 602: 
 603: DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
 604:   0, 1, "",
 605:   "Make WINDOW (or the selected window) fill the screen.")
 606:   (w)
 607:      Lisp_Object w;
 608: {
 609:   window_loop (3, !NULL (w) ? w : selected_window);
 610:   return Qnil;
 611: }
 612: 
 613: DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
 614:   1, 1, "bDelete windows on (buffer): ",
 615:   "Delete all windows showing BUFFER.")
 616:   (buffer)
 617:      Lisp_Object buffer;
 618: {
 619:   if (!NULL (buffer))
 620:     {
 621:       buffer = Fget_buffer (buffer);
 622:       CHECK_BUFFER (buffer, 0);
 623:       window_loop (4, buffer);
 624:     }
 625:   return Qnil;
 626: }
 627: 
 628: DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
 629:   Sreplace_buffer_in_windows,
 630:   1, 1, "bReplace buffer in windows: ",
 631:   "Replace BUFFER with some other buffer in all windows showing it.")
 632:   (buffer)
 633:      Lisp_Object buffer;
 634: {
 635:   if (!NULL (buffer))
 636:     {
 637:       buffer = Fget_buffer (buffer);
 638:       CHECK_BUFFER (buffer, 0);
 639:       window_loop (6, buffer);
 640:     }
 641:   return Qnil;
 642: }
 643: 
 644: /* Set the height of WINDOW and all its inferiors.  */
 645: /* Normally the window is deleted if it gets too small.
 646:    nodelete nonzero means do not do this.
 647:    (The caller should check later and do so if appropriate)  */
 648: 
 649: set_window_height (window, height, nodelete)
 650:      Lisp_Object window;
 651:      int height;
 652:      int nodelete;
 653: {
 654:   register struct window *w = XWINDOW (window);
 655:   register struct window *c;
 656:   int oheight = XFASTINT (w->height);
 657:   int top, pos, lastbot, opos, lastobot;
 658:   Lisp_Object child;
 659: 
 660:   if (window_min_height < 2)
 661:     window_min_height = 2;
 662: 
 663:   if (!nodelete &&
 664:       height < (EQ(window, minibuf_window) ? 1 : window_min_height))
 665:     {
 666:       Fdelete_window (window);
 667:       return;
 668:     }
 669: 
 670:   XFASTINT (w->last_modified) = 0;
 671:   windows_or_buffers_changed++;
 672:   XFASTINT (w->height) = height;
 673:   if (!NULL (w->hchild))
 674:     {
 675:       for (child = w->hchild; !NULL (child); child = XWINDOW (child)->next)
 676:     {
 677:       XWINDOW (child)->top = w->top;
 678:       set_window_height (child, height, nodelete);
 679:     }
 680:     }
 681:   else if (!NULL (w->vchild))
 682:     {
 683:       lastbot = top = XFASTINT (w->top);
 684:       lastobot = 0;
 685:       for (child = w->vchild; !NULL (child); child = c->next)
 686:     {
 687:       c = XWINDOW (child);
 688: 
 689:       opos = lastobot + XFASTINT (c->height);
 690: 
 691:       XFASTINT (c->top) = lastbot;
 692: 
 693:       pos = (((opos * height) << 1) + oheight) / (oheight << 1);
 694: 
 695:       /* Avoid confusion: inhibit deletion of child if becomes too small */
 696:       set_window_height (child, pos + top - lastbot, 1);
 697: 
 698:       /* Now advance child to next window,
 699: 	     and set lastbot if child was not just deleted.  */
 700:       lastbot = pos + top, lastobot = opos;
 701:     }
 702:       /* Now delete any children that became too small.  */
 703:       if (!nodelete)
 704:     for (child = w->vchild; !NULL (child); child = XWINDOW (child)->next)
 705:       {
 706:         set_window_height (child, XINT (XWINDOW (child)->height), 0);
 707:       }
 708:     }
 709: }
 710: 
 711: /* Recursively set width of WINDOW and its inferiors. */
 712: 
 713: set_window_width (window, width, nodelete)
 714:      Lisp_Object window;
 715:      int width;
 716:      int nodelete;
 717: {
 718:   register struct window *w = XWINDOW (window);
 719:   register struct window *c;
 720:   int owidth = XFASTINT (w->width);
 721:   int left, pos, lastright, opos, lastoright;
 722:   Lisp_Object child;
 723: 
 724:   if (!nodelete && width < window_min_width)
 725:     {
 726:       Fdelete_window (window);
 727:       return;
 728:     }
 729: 
 730:   XFASTINT (w->last_modified) = 0;
 731:   XFASTINT (w->width) = width;
 732:   if (!NULL (w->vchild))
 733:     {
 734:       for (child = w->vchild; !NULL (child); child = XWINDOW (child)->next)
 735:     {
 736:       XWINDOW (child)->left = w->left;
 737:       set_window_width (child, width, nodelete);
 738:     }
 739:     }
 740:   else if (!NULL (w->hchild))
 741:     {
 742:       lastright = left = XFASTINT (w->left);
 743:       lastoright = 0;
 744:       for (child = w->hchild; !NULL (child); child = c->next)
 745:     {
 746:       c = XWINDOW (child);
 747: 
 748:       opos = lastoright + XFASTINT (c->width);
 749: 
 750:       XFASTINT (c->left) = lastright;
 751: 
 752:       pos = (((opos * width) << 1) + owidth) / (owidth << 1);
 753: 
 754:       /* Inhibit deletion for becoming too small */
 755:       set_window_width (child, pos + left - lastright, 1);
 756: 
 757:       /* Now advance child to next window,
 758: 	     and set lastright if child was not just deleted.  */
 759:       lastright = pos + left, lastoright = opos;
 760:     }
 761:       /* Delete children that became too small */
 762:       if (!nodelete)
 763:     for (child = w->hchild; !NULL (child); child = XWINDOW (child)->next)
 764:       {
 765:         set_window_width (child, XINT (XWINDOW (child)->width), 0);
 766:       }
 767:     }
 768: }
 769: 
 770: static int window_select_count;
 771: 
 772: DEFUN ("show-buffer", Fshow_buffer, Sshow_buffer, 2, 2, 0,
 773:   "Make WINDOW display BUFFER as its contents.\n\
 774: BUFFER can be a buffer or buffer name.")
 775:   (window, buffer)
 776:      Lisp_Object window, buffer;
 777: {
 778:   Lisp_Object tem;
 779:   struct window *w = decode_window (window);
 780: 
 781:   buffer = Fget_buffer (buffer);
 782:   CHECK_BUFFER (buffer, 1);
 783: 
 784:   if (NULL (XBUFFER (buffer)->name))
 785:     error ("Attempt to display deleted buffer");
 786: 
 787:   tem = w->buffer;
 788:   if (!NULL (tem))
 789:     unshow_buffer (w);
 790: 
 791:   w->buffer = buffer;
 792:   Fset_marker (w->pointm,
 793:            make_number (XBUFFER (buffer) == bf_cur
 794:                 ? point : XBUFFER (buffer)->text.pointloc),
 795:            buffer);
 796:   Fset_marker (w->start, make_number (XBUFFER (buffer)->last_window_start),
 797:            buffer);
 798:   XFASTINT (w->last_modified) = 0;
 799:   windows_or_buffers_changed++;
 800:   if (EQ (window, selected_window))
 801:     Fset_buffer (buffer);
 802: 
 803:   return Qnil;
 804: }
 805: 
 806: /* Record info on buffer window w is displaying
 807:  when it is about to cease to display that buffer.  */
 808: 
 809: unshow_buffer (w)
 810:      struct window *w;
 811: {
 812:   Lisp_Object buf;
 813:   buf = w->buffer;
 814: 
 815:   if (XBUFFER (buf) != XMARKER (w->pointm)->buffer)
 816:     abort ();
 817: 
 818:   if (w != XWINDOW (selected_window)
 819:       && EQ (buf, XWINDOW (selected_window)->buffer))
 820:     return;
 821: 
 822:   if (XBUFFER (buf) == bf_cur)
 823:     {
 824:       if (w != XWINDOW (selected_window))
 825:     point = marker_position (w->pointm);
 826:     }
 827:   else
 828:     XBUFFER (buf)->text.pointloc =
 829:       marker_position (w->pointm);
 830:   XBUFFER (buf)->last_window_start =
 831:     marker_position (w->start);
 832: }
 833: 
 834: DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0,
 835:   "Select WINDOW.  Most editing will apply to WINDOW's buffer.\n\
 836: The main editor command loop selects the buffer of the selected window\n\
 837: before each command.")
 838:   (window)
 839:      Lisp_Object window;
 840: {
 841:   register struct window *w = XWINDOW (window);
 842:   register struct window *ow = XWINDOW (selected_window);
 843: 
 844:   CHECK_WINDOW (window, 0);
 845: 
 846:   if (NULL (w->buffer))
 847:     error ("Trying to select window with no buffer");
 848: 
 849:   XFASTINT (w->use_time) = ++window_select_count;
 850:   if (EQ (window, selected_window))
 851:     return window;
 852: 
 853:   if (bf_cur == XBUFFER (ow->buffer))
 854:     Fset_marker (ow->pointm, make_number (point), ow->buffer);
 855: 
 856:   selected_window = window;
 857: 
 858:   record_buffer (w->buffer);
 859:   Fset_buffer (w->buffer);
 860:   if (bf_cur == XBUFFER (ow->buffer))
 861:     {
 862:       /* If the new and old windows show the same buffer,
 863: 	 Fset_buffer did nothing.  So we must switch to
 864: 	 the new buffer's value of point.  */
 865:       SetPoint (marker_position (w->pointm));
 866:       if (point < FirstCharacter)
 867:     point = FirstCharacter;
 868:       if (point > NumCharacters + 1)
 869:     point = NumCharacters + 1;
 870:     }
 871: 
 872:   windows_or_buffers_changed++;
 873: 
 874:   return window;
 875: }
 876: 
 877: DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 2, 0,
 878:   "Make BUFFER appear in some window but don't select it.\n\
 879: BUFFER can be a buffer or a buffer name.\n\
 880: If BUFFER is shown already in some window, just uses that one,\n\
 881: unless the window is the selected window and NOTTHISWINDOW is non-nil.\n\
 882: Returns the window displaying BUFFER.")
 883:   (buffer, notthiswindow)
 884:      Lisp_Object buffer, notthiswindow;
 885: {
 886:   Lisp_Object window;
 887:   buffer = Fget_buffer (buffer);
 888:   CHECK_BUFFER (buffer, 0);
 889: 
 890:   if (NULL (notthiswindow)
 891:       && XBUFFER (XWINDOW (selected_window)->buffer) == XBUFFER (buffer))
 892:     return selected_window;
 893: 
 894:   window = Fget_buffer_window (buffer);
 895:   if (!NULL (window)
 896:       && (NULL (notthiswindow) || !EQ (window, selected_window)))
 897:     return window;
 898: 
 899:   if (pop_up_windows)
 900:     {
 901:       /* Don't try to create a window if would get an error */
 902:       if (window_min_height < 2)
 903:     window_min_height = 2;
 904:       if (split_height_threshold < window_min_height << 1)
 905:     split_height_threshold = window_min_height << 1;
 906: 
 907:       window = Fget_largest_window ();
 908:       if (window_height (window) >= split_height_threshold
 909:       &&
 910:       XFASTINT (XWINDOW (window)->width) != screen_width)
 911:     window = Fsplit_window (window, Qnil, Qnil);
 912:       else
 913:     {
 914:       window = Fget_lru_window ();
 915:       if ((EQ (window, selected_window)
 916:            || (EQ (selected_window, minibuf_window)
 917:            && EQ (window, XWINDOW (minibuf_window)->prev)))
 918:           && window_height (window) >= window_min_height << 1)
 919:         window = Fsplit_window (window, Qnil, Qnil);
 920:     }
 921:     }
 922:   else
 923:     window = Fget_lru_window ();
 924: 
 925:   Fshow_buffer (window, buffer);
 926:   return window;
 927: }
 928: 
 929: temp_output_buffer_show (buf)
 930:      Lisp_Object buf;
 931: {
 932:   struct buffer *old = bf_cur;
 933:   Lisp_Object window;
 934: 
 935:   Fset_buffer (buf);
 936:   XBUFFER (buf)->save_modified = bf_modified;
 937:   SetPoint (1);
 938:   bf_head_clip = 1;
 939:   bf_tail_clip = 0;
 940:   clip_changed = 1;
 941:   SetBfp (old);
 942: 
 943:   window = Fdisplay_buffer (buf, Qnil);
 944:   XFASTINT (XWINDOW (window)->hscroll) = 0;
 945:   Fset_marker (XWINDOW (window)->start, make_number (1), buf);
 946:   Fset_marker (XWINDOW (window)->pointm, make_number (1), buf);
 947: }
 948: 
 949: make_dummy_parent (window)
 950:      Lisp_Object window;
 951: {
 952:   Lisp_Object old, new;
 953:   register struct window *o, *p;
 954:   old = window;
 955:   XSETTYPE (old, Lisp_Vector);
 956:   new = Fcopy_sequence (old);
 957:   XSETTYPE (new, Lisp_Window);
 958: 
 959:   o = XWINDOW (old);
 960:   p = XWINDOW (new);
 961:   XFASTINT (p->sequence_number) = ++sequence_number;
 962: 
 963:   /* Put new into window structure in place of window */
 964:   replace_window (window, new);
 965: 
 966:   o->next = Qnil;
 967:   o->prev = Qnil;
 968:   o->vchild = Qnil;
 969:   o->hchild = Qnil;
 970:   o->parent = new;
 971: 
 972:   p->start = Qnil;
 973:   p->pointm = Qnil;
 974:   p->buffer = Qnil;
 975: }
 976: 
 977: DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
 978:   "Split WINDOW, putting SIZE lines in the first of the pair.\n\
 979: WINDOW defaults to selected one and SIZE to half its size.\n\
 980: If optional third arg HOR-FLAG is non-nil, split side by side\n\
 981: and put SIZE columns in the first of the pair.")
 982:   (window, chsize, horflag)
 983:      Lisp_Object window, chsize, horflag;
 984: {
 985:   Lisp_Object new;
 986:   register struct window *o, *p;
 987:   int size;
 988: 
 989:   if (NULL (window))
 990:     window = selected_window;
 991:   else
 992:     CHECK_WINDOW (window, 0);
 993: 
 994:   o = XWINDOW (window);
 995: 
 996:   if (NULL (chsize))
 997:     {
 998:       if (!NULL (horflag))
 999:     size = XFASTINT (o->width) >> 1;
1000:       else
1001:     size = XFASTINT (o->height) >> 1;
1002:     }
1003:   else
1004:     {
1005:       CHECK_NUMBER (chsize, 1);
1006:       size = XINT (chsize);
1007:     }
1008: 
1009:   if (EQ (window, minibuf_window))
1010:     error ("Attempt to split minibuffer window");
1011: 
1012:   if (NULL (horflag))
1013:     {
1014:       if (window_min_height < 2)
1015:     window_min_height = 2;
1016: 
1017:       if (size < window_min_height ||
1018:       size + window_min_height > XFASTINT (o->height))
1019:     args_out_of_range_3 (window, chsize, horflag);
1020:       if (NULL (o->parent) ||
1021:       NULL (XWINDOW (o->parent)->vchild))
1022:     {
1023:       make_dummy_parent (window);
1024:       new = o->parent;
1025:       XWINDOW (new)->vchild = window;
1026:     }
1027:     }
1028:   else
1029:     {
1030:       if (size < window_min_width ||
1031:       size + window_min_width > XFASTINT (o->width))
1032:     args_out_of_range_3 (window, chsize, horflag);
1033:       if (NULL (o->parent) ||
1034:       NULL (XWINDOW (o->parent)->hchild))
1035:     {
1036:       make_dummy_parent (window);
1037:       new = o->parent;
1038:       XWINDOW (new)->hchild = window;
1039:     }
1040:     }
1041: 
1042:   /* Now we know that window's parent is a vertical combination
1043:      if we are dividing vertically, or a horizontal combination
1044:      if we are making side-by-side windows */
1045: 
1046:   windows_or_buffers_changed++;
1047:   new = make_window ();
1048:   p = XWINDOW (new);
1049: 
1050:   p->next = o->next;
1051:   if (!NULL (p->next))
1052:     XWINDOW (p->next)->prev = new;
1053:   p->prev = window;
1054:   o->next = new;
1055:   p->parent = o->parent;
1056: 
1057:   Fshow_buffer (new, o->buffer);
1058: 
1059:   /* Apportion the available screen space among the two new windows */
1060: 
1061:   if (!NULL (horflag))
1062:     {
1063:       p->height = o->height;
1064:       p->top = o->top;
1065:       XFASTINT (p->width) = XFASTINT (o->width) - size;
1066:       XFASTINT (o->width) = size;
1067:       XFASTINT (p->left) = XFASTINT (o->left) + size;
1068:     }
1069:   else
1070:     {
1071:       p->left = o->left;
1072:       p->width = o->width;
1073:       XFASTINT (p->height) = XFASTINT (o->height) - size;
1074:       XFASTINT (o->height) = size;
1075:       XFASTINT (p->top) = XFASTINT (o->top) + size;
1076:     }
1077: 
1078:   return new;
1079: }
1080: 
1081: DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
1082:   "Make current window ARG lines bigger.\n\
1083: From program, optional second arg non-nil means grow sideways ARG columns.")
1084:   (n, side)
1085:      Lisp_Object n, side;
1086: {
1087:   CHECK_NUMBER (n, 0);
1088:   change_window_height (XINT (n), !NULL (side));
1089:   return Qnil;
1090: }
1091: 
1092: DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
1093:   "Make current window ARG lines smaller.\n\
1094: From program, optional second arg non-nil means shrink sideways ARG columns.")
1095:   (n, side)
1096:      Lisp_Object n, side;
1097: {
1098:   CHECK_NUMBER (n, 0);
1099:   change_window_height (-XINT (n), !NULL (side));
1100:   return Qnil;
1101: }
1102: 
1103: int
1104: window_height (window)
1105:      Lisp_Object window;
1106: {
1107:   register struct window *p = XWINDOW (window);
1108:   return XFASTINT (p->height);
1109: }
1110: 
1111: int
1112: window_width (window)
1113:      Lisp_Object window;
1114: {
1115:   register struct window *p = XWINDOW (window);
1116:   return XFASTINT (p->width);
1117: }
1118: 
1119: #define MINSIZE(window) \
1120:   (widthflag ? window_min_width  \
1121:    : (EQ (window, minibuf_window) ? 1 : window_min_height))
1122: 
1123: #define CURBEG(w) \
1124:   *(widthflag ? (int *) &w->left : (int *) &w->top)
1125: 
1126: #define CURSIZE(w) \
1127:   *(widthflag ? (int *) &w->width : (int *) &w->height)
1128: 
1129: /* Unlike set_window_height, this function
1130:  also changes the heights of the siblings so as to
1131:  keep everything consistent. */
1132: 
1133: change_window_height (delta, widthflag)
1134:      int delta, widthflag;
1135: {
1136:   Lisp_Object window, parent, tem;
1137:   register struct window *p;
1138:   int *sizep;
1139:   int (*sizefun) () = widthflag ? window_width : window_height;
1140:   int (*setsizefun) () = widthflag ? set_window_width : set_window_height;
1141:   int opht, maxdelta;
1142: 
1143:   window = selected_window;
1144:   while (1)
1145:     {
1146:       p = XWINDOW (window);
1147:       parent = p->parent;
1148:       if (NULL (parent))
1149:     {
1150:       if (widthflag)
1151:         error ("No other window to side of this one");
1152:       break;
1153:     }
1154:       if (widthflag ? !NULL (XWINDOW (parent)->hchild)
1155:       : !NULL (XWINDOW (parent)->vchild))
1156:     break;
1157:       window = parent;
1158:     }
1159: 
1160:   sizep = &CURSIZE (p);
1161: 
1162:   if (*sizep + delta < MINSIZE (window))
1163:     {
1164:       Fdelete_window (window);
1165:       return;
1166:     }
1167: 
1168:   maxdelta = (!NULL (parent) ? (*sizefun) (parent) - *sizep
1169:           : (tem = (!NULL (p->next) ? p->next : p->prev),
1170:          (*sizefun) (tem) - MINSIZE (tem)));
1171: 
1172:   if (delta > maxdelta)
1173:     /* This case traps trying to make the minibuffer
1174:        the full screen, or make the only window aside from the
1175:        minibuffer the full screen.  */
1176:     delta = maxdelta;
1177: 
1178:   if (!NULL (p->next) &&
1179:       (*sizefun) (p->next) - delta >= MINSIZE (p->next))
1180:     {
1181:       (*setsizefun) (p->next, (*sizefun) (p->next) - delta, 0);
1182:       (*setsizefun) (window, *sizep + delta, 0);
1183:       CURBEG (XWINDOW (p->next)) += delta;
1184:       /* This does not change size of p->next,
1185: 	 but it propagates the new top edge to its children */
1186:       (*setsizefun) (p->next, (*sizefun) (p->next), 0);
1187:     }
1188:   else if (!NULL (p->prev) &&
1189:        (*sizefun) (p->prev) - delta >= MINSIZE (p->prev))
1190:     {
1191:       (*setsizefun) (p->prev, (*sizefun) (p->prev) - delta, 0);
1192:       CURBEG (p) -= delta;
1193:       (*setsizefun) (window, *sizep + delta, 0);
1194:     }
1195:   else
1196:     {
1197:       opht = (*sizefun) (parent);
1198: 
1199:       delta = (int) ((float) (delta * opht)
1200:              / (float) (opht - *sizep - delta));
1201:       /* Add delta lines or columns to this window, and to the parent,
1202: 	 keeping things consistent while not affecting siblings.  */
1203:       CURSIZE (XWINDOW (parent)) = opht + delta;
1204:       (*setsizefun) (window, *sizep + delta, 0);
1205:       /* Squeeze out delta lines or columns from our parent,
1206: 	 shriking this window and siblings proportionately.
1207: 	 This brings parent back to correct size.
1208: 	 Delta was calculated so this makes this window the desired size,
1209: 	 taking it all out of the siblings.  */
1210:       (*setsizefun) (parent, opht, 0);
1211:     }
1212: 
1213:   XFASTINT (p->last_modified) = 0;
1214: }
1215: 
1216: static
1217: window_scroll (window, n)
1218:      Lisp_Object window;
1219:      int n;
1220: {
1221:   register struct window *w = XWINDOW (window);
1222:   register int opoint = point;
1223:   register int ht, pos;
1224:   int lose;
1225:   Lisp_Object tem;
1226: 
1227:   ht = XFASTINT (w->height) - !EQ (window, minibuf_window);
1228: 
1229:   XFASTINT (tem) = point;
1230:   tem = Fpos_visible_in_window_p (tem, window);
1231: 
1232:   if (NULL (tem))
1233:     {
1234:       Fvertical_motion (make_number (- ht / 2));
1235:       XFASTINT (tem) = point;
1236:       Fset_marker (w->start, tem, w->buffer);
1237:       w->force_start = Qt;
1238:     }
1239: 
1240:   SetPoint (marker_position (w->start));
1241:   lose = n < 0 && point == FirstCharacter;
1242:   Fvertical_motion (make_number (n));
1243:   pos = point;
1244:   SetPoint (opoint);
1245: 
1246:   if (lose)
1247:     Fsignal (Qbeginning_of_buffer, Qnil);
1248: 
1249:   if (pos < NumCharacters + 1)
1250:     {
1251:       Fset_marker (w->start, make_number (pos), w->buffer);
1252:       w->redo_mode_line = Qt;
1253:       XFASTINT (w->last_modified) = 0;
1254:       if (pos > opoint)
1255:     SetPoint (pos);
1256:       if (n < 0)
1257:     {
1258:       SetPoint (pos);
1259:       tem = Fvertical_motion (make_number (ht));
1260:       if (point > opoint || XFASTINT (tem) < ht)
1261:         SetPoint (opoint);
1262:       else
1263:         Fvertical_motion (make_number (-1));
1264:     }
1265:     }
1266:   else
1267:     Fsignal (Qend_of_buffer, Qnil);
1268: }
1269: 
1270: scroll_command (n, direction)
1271:      Lisp_Object n;
1272:      int direction;
1273: {
1274:   register int defalt
1275:     = direction * (window_height (selected_window) - 1
1276:            - next_screen_context_lines);
1277: 
1278:   if (NULL (n))
1279:     window_scroll (selected_window, defalt);
1280:   else if (EQ (n, Qminus))
1281:     window_scroll (selected_window, - defalt);
1282:   else
1283:     {
1284:       n = Fprefix_numeric_value (n);
1285:       window_scroll (selected_window, XINT (n) * direction);
1286:     }
1287: }
1288: 
1289: DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
1290:   "Scroll text of current window upward ARG lines; or near full screen if no ARG.\n\
1291: When calling from a program, supply a number as argument or nil.")
1292:   (n)
1293:      Lisp_Object n;
1294: {
1295:   scroll_command (n, 1);
1296:   return Qnil;
1297: }
1298: 
1299: DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
1300:   "Scroll text of current window downward ARG lines; or near full screen if no ARG.\n\
1301: When calling from a program, supply a number as argument or nil.")
1302:   (n)
1303:      Lisp_Object n;
1304: {
1305:   scroll_command (n, -1);
1306:   return Qnil;
1307: }
1308: 
1309: DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 1, 1, "P",
1310:   "Scroll selected window display ARG columns left.\n\
1311: Default for ARG is window width minus 2.")
1312:   (arg)
1313:      Lisp_Object arg;
1314: {
1315:   if (NULL (arg))
1316:     XFASTINT (arg) = XFASTINT (XWINDOW (selected_window)->width) - 2;
1317:   else
1318:     arg = Fprefix_numeric_value (arg);
1319: 
1320:   return Fset_window_hscroll (selected_window,
1321:                   make_number (XINT (XWINDOW (selected_window)->hscroll)
1322:                        + XINT (arg)));
1323: }
1324: 
1325: DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 1, 1, "P",
1326:   "Scroll selected window display ARG columns right.\n\
1327: Default for ARG is window width minus 2.")
1328:   (arg)
1329:      Lisp_Object arg;
1330: {
1331:   if (NULL (arg))
1332:     XFASTINT (arg) = XFASTINT (XWINDOW (selected_window)->width) - 2;
1333:   else
1334:     arg = Fprefix_numeric_value (arg);
1335: 
1336:   return Fset_window_hscroll (selected_window,
1337:                   make_number (XINT (XWINDOW (selected_window)->hscroll)
1338:                        - XINT (arg)));
1339: }
1340: 
1341: DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
1342:   "Scroll text of next window upward ARG lines; or near full screen if no ARG.\n\
1343: The next window is the one below the current one; or the one at the top\n\
1344: if the current one is at the bottom.\n\
1345: When calling from a program, supply a number as argument or nil.")
1346:   (n)
1347:      Lisp_Object n;
1348: {
1349:   Lisp_Object window;
1350:   struct buffer *old = bf_cur;
1351:   register int ht;
1352:   register int opoint = point;
1353: 
1354:   window = Fnext_window (selected_window, Qnil);
1355:   ht = window_height (window) - 1;
1356: 
1357:   if (EQ (window, selected_window))
1358:     error ("There is no other window");
1359: 
1360:   Fset_buffer (XWINDOW (window)->buffer);
1361:   SetPoint (marker_position (XWINDOW (window)->pointm));
1362: 
1363:   if (NULL (n))
1364:     window_scroll (window, ht - next_screen_context_lines);
1365:   else if (EQ (n, Qminus))
1366:     window_scroll (window, next_screen_context_lines - ht);
1367:   else
1368:     {
1369:       if (XTYPE (n) == Lisp_Cons)
1370:     n = Fcar (n);
1371:       CHECK_NUMBER (n, 0);
1372:       window_scroll (window, XINT (n));
1373:     }
1374: 
1375:   Fset_marker (XWINDOW (window)->pointm, make_number (point), Qnil);
1376:   SetBfp (old);
1377:   SetPoint (opoint);
1378:   return Qnil;
1379: }
1380: 
1381: DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
1382:   "Center point in window and redisplay screen.  With ARG, put point on line ARG.\n\
1383: The desired position of point is always relative to the current window.\n\
1384: If there is no ARG (i.e., it is nil) then the entire screen is redisplayed.")
1385:   (n)
1386:      Lisp_Object n;
1387: {
1388:   int ht = window_height (selected_window)
1389:         - !EQ (selected_window, minibuf_window);
1390:   struct window *w = XWINDOW (selected_window);
1391:   register int opoint = point;
1392: 
1393:   if (NULL (n))
1394:     {
1395:       extern int screen_garbaged;
1396:       screen_garbaged++;
1397:       XFASTINT (n) = ht / 2;
1398:     }
1399:   else
1400:     {
1401:       n = Fprefix_numeric_value (n);
1402:       CHECK_NUMBER (n, 0);
1403:     }
1404: 
1405:   if (XINT (n) < 0)
1406:     XSETINT (n, XINT (n) + ht);
1407: 
1408:   XSETINT (n, - XINT (n));
1409: 
1410:   Fvertical_motion (n);
1411:   Fset_marker (w->start, make_number (point), w->buffer);
1412: 
1413:   SetPoint (opoint);
1414:   w->force_start = Qt;
1415: 
1416:   return Qnil;
1417: }
1418: 
1419: DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
1420:   1, 1, "P",
1421:   "Position point relative to window.\n\
1422: With no argument, position at text at center of window.\n\
1423: An argument specifies screen line; zero means top of window,\n\
1424: negative means relative to bottom of window.")
1425:   (arg)
1426:      Lisp_Object arg;
1427: {
1428:   register struct window *w = XWINDOW (selected_window);
1429:   int height = XFASTINT (w->height);
1430:   register int start;
1431: 
1432:   if (!EQ (selected_window, minibuf_window)) height--;
1433: 
1434:   if (NULL (arg))
1435:     XFASTINT (arg) = height / 2;
1436:   else
1437:     {
1438:       arg = Fprefix_numeric_value (arg);
1439:       if (XINT (arg) < 0)
1440:     XSETINT (arg, XINT (arg) + height);
1441:     }
1442: 
1443:   start = marker_position (w->start);
1444:   if (start < FirstCharacter || start > NumCharacters + 1)
1445:     {
1446:       Fvertical_motion (make_number (- height / 2));
1447:       Fset_marker (w->start, make_number (point), w->buffer);
1448:       w->force_start = Qt;
1449:       start = point;
1450:     }
1451:   else
1452:     SetPoint (start);
1453: 
1454:   return Fvertical_motion (arg);
1455: }
1456: 
1457: struct saved_window
1458:   {
1459:     Lisp_Object window;
1460:     Lisp_Object buffer, start, pointm, mark;
1461:     Lisp_Object left, top, width, height, hscroll;
1462:     Lisp_Object parent, prev;
1463:   };
1464: 
1465: struct save_window_data
1466:   {
1467:     long size;
1468:     struct Lisp_Vector *unused;
1469:     Lisp_Object nsaved;
1470:     Lisp_Object current_window;
1471:     Lisp_Object current_buffer;
1472:     struct saved_window info[1];
1473:   };
1474: 
1475: Lisp_Object
1476: save_window_restore (arg)
1477:      Lisp_Object arg;
1478: {
1479:   register struct window *w;
1480:   register struct save_window_data *data = (struct save_window_data *) XINTPTR (arg);
1481:   register struct saved_window *p = data->info;
1482:   Lisp_Object tem;
1483:   register int k;
1484: 
1485:   windows_or_buffers_changed++;
1486:   for (k = 0; k < XFASTINT (data->nsaved); k++, p++)
1487:     {
1488:       w = XWINDOW (p->window);
1489:       w->next = Qnil;
1490: 
1491:       if (!NULL (p->parent))
1492:     w->parent = data->info[XFASTINT (p->parent)].window;
1493:       else
1494:     w->parent = Qnil;
1495: 
1496:       if (!NULL (p->prev))
1497:     {
1498:       w->prev = data->info[XFASTINT (p->prev)].window;
1499:       XWINDOW (w->prev)->next = p->window;
1500:     }
1501:       else
1502:     {
1503:       w->prev = Qnil;
1504:       if (!NULL (w->parent))
1505:         {
1506:           if (EQ (p->width, XWINDOW (w->parent)->width))
1507:         {
1508:           XWINDOW (w->parent)->vchild = p->window;
1509:           XWINDOW (w->parent)->hchild = Qnil;
1510:         }
1511:           else
1512:         {
1513:           XWINDOW (w->parent)->hchild = p->window;
1514:           XWINDOW (w->parent)->vchild = Qnil;
1515:         }
1516:         }
1517:     }
1518:       w->left = p->left;
1519:       w->top = p->top;
1520:       w->width = p->width;
1521:       w->height = p->height;
1522:       w->hscroll = p->hscroll;
1523:       XFASTINT (w->last_modified) = 0;
1524: 
1525:       /* Reinstall the saved buffer and pointers into it.  */
1526:       if (NULL (p->buffer))
1527:     w->buffer = p->buffer;
1528:       else
1529:     {
1530:       if (!NULL (XBUFFER (p->buffer)->name))
1531:         /* If saved buffer is alive, install it.  */
1532:         {
1533:           w->buffer = p->buffer;
1534:           Fset_marker (w->start, Fmarker_position (p->start), w->buffer);
1535:           Fset_marker (w->pointm, Fmarker_position (p->pointm), w->buffer);
1536:         }
1537:       else if (NULL (XBUFFER (w->buffer)->name))
1538:         /* Else if window's old buffer is dead too, get a live one.  */
1539:         {
1540:           w->buffer = Fcdr (Fcar (Vbuffer_alist));
1541:           /* Set window markers at start of buffer.
1542: 		 Rely on Fset_marker to put them within the restriction.  */
1543:           Fset_marker (w->start, make_number (0), w->buffer);
1544:           Fset_marker (w->pointm, make_number (0), w->buffer);
1545:         }
1546:       unchain_marker (p->start);
1547:       unchain_marker (p->pointm);
1548: 
1549:       tem = p->mark;
1550:       if (NULL (tem))
1551:         XBUFFER (w->buffer)->mark = Qnil;
1552:       else
1553:         {
1554:           if (NULL (XBUFFER (w->buffer)->mark))
1555:         XBUFFER (w->buffer)->mark = Fmake_marker ();
1556: 
1557:           Fset_marker (XBUFFER (w->buffer)->mark,
1558:                Fmarker_position (p->mark), w->buffer);
1559:           unchain_marker (p->mark);
1560:         }
1561:     }
1562:     }
1563: 
1564:   Fselect_window (data->current_window);
1565:   Fset_buffer (data->current_buffer);
1566: 
1567:   free (data);
1568:   return Qnil;
1569: }
1570: 
1571: count_windows (window)
1572:      struct window *window;
1573: {
1574:   int count = 1;
1575:   if (!NULL (window->next))
1576:     count += count_windows (XWINDOW (window->next));
1577:   if (!NULL (window->vchild))
1578:     count += count_windows (XWINDOW (window->vchild));
1579:   if (!NULL (window->hchild))
1580:     count += count_windows (XWINDOW (window->hchild));
1581:   return count;
1582: }
1583: 
1584: #define SAVE_DATA_SIZE(n_windows) \
1585:   ((n_windows - 1) * sizeof (struct saved_window) \
1586:    + sizeof (struct save_window_data))
1587: 
1588: Lisp_Object
1589: save_window_save ()
1590: {
1591:   Lisp_Object root;
1592:   int n_windows;
1593:   struct save_window_data *data;
1594:   Lisp_Object tem;
1595:   int size;
1596: 
1597:   root = XWINDOW (minibuf_window)->prev;
1598:   n_windows = count_windows (XWINDOW (root));
1599: 
1600:   size = SAVE_DATA_SIZE (n_windows);
1601:   data = (struct save_window_data *) xmalloc (size);
1602: 
1603:   data->size = (size - sizeof (long) - sizeof (struct Lisp_Vector *))
1604:     / sizeof (Lisp_Object);
1605:   XFASTINT (data->nsaved) = n_windows;
1606:   data->current_window = selected_window;
1607:   XSET (data->current_buffer, Lisp_Buffer, bf_cur);
1608: 
1609:   save_window_save_1 (root, data, 0);
1610: 
1611:   XSET (tem, Lisp_Temp_Vector, data);
1612:   return tem;
1613: }
1614: 
1615: save_window_save_1 (window, data, i)
1616:      Lisp_Object window;
1617:      struct save_window_data *data;
1618:      int i;
1619: {
1620:   struct saved_window *p;
1621:   struct window *w;
1622:   Lisp_Object tem;
1623: 
1624:   for (;!NULL (window); window = w->next)
1625:     {
1626:       p = &data->info[i];
1627:       w = XWINDOW (window);
1628: 
1629:       XFASTINT (w->temslot) = i++;
1630:       p->window = window;
1631:       p->buffer = w->buffer;
1632:       p->left = w->left;
1633:       p->top = w->top;
1634:       p->width = w->width;
1635:       p->height = w->height;
1636:       p->hscroll = w->hscroll;
1637:       if (!NULL (w->buffer))
1638:     {
1639:       if (EQ (window, selected_window)
1640:           && XBUFFER (w->buffer) == bf_cur)
1641:         p->pointm = Fpoint_marker ();
1642:       else
1643:         p->pointm = Fcopy_marker (w->pointm);
1644: 
1645:       p->start = Fcopy_marker (w->start);
1646: 
1647:       tem = XBUFFER (w->buffer)->mark;
1648:       if (!NULL (tem))
1649:         p->mark = Fcopy_marker (tem);
1650:       else
1651:         p->mark = Qnil;
1652:     }
1653:       else
1654:     {
1655:       p->pointm = Qnil;
1656:       p->start = Qnil;
1657:       p->mark = Qnil;
1658:     }
1659: 
1660:       if (NULL (w->parent))
1661:     p->parent = Qnil;
1662:       else
1663:     p->parent = XWINDOW (w->parent)->temslot;
1664: 
1665:       if (NULL (w->prev))
1666:     p->prev = Qnil;
1667:       else
1668:     p->prev = XWINDOW (w->prev)->temslot;
1669: 
1670:       if (!NULL (w->vchild))
1671:     i = save_window_save_1 (w->vchild, data, i);
1672:       if (!NULL (w->hchild))
1673:     i = save_window_save_1 (w->hchild, data, i);
1674:     }
1675: 
1676:   return i;
1677: }
1678: 
1679: DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
1680:   0, UNEVALLED, 0,
1681:   "Execute body, preserving window sizes and contents.\n\
1682: Restores which buffer appears in which window, where display starts,\n\
1683: as well as the current buffer.\n\
1684: Does not restore the value of point in that buffer.")
1685:   (args)
1686:      Lisp_Object args;
1687: {
1688:   Lisp_Object tem, val;
1689:   struct gcpro gcpro1;
1690:   int count = specpdl_ptr - specpdl;
1691: 
1692:   tem = save_window_save ();
1693: 
1694:   GCPRO1 (*XOBJFWD (tem));
1695:   gcpro1.nvars
1696:     = SAVE_DATA_SIZE (XFASTINT (((struct save_window_data *) XINTPTR (tem))
1697:                 ->nsaved))
1698:       / 4;
1699: 
1700:   record_unwind_protect (save_window_restore, tem);
1701:   val = Fprogn (args);
1702:   UNGCPRO;
1703:   unbind_to (count);
1704:   return val;
1705: }
1706: 
1707: init_window_once ()
1708: {
1709:   extern Lisp_Object get_minibuffer ();
1710:   Lisp_Object root_window;
1711: 
1712:   root_window = make_window ();
1713:   minibuf_window = make_window ();
1714: 
1715:   XWINDOW (root_window)->next = minibuf_window;
1716:   XWINDOW (minibuf_window)->prev = root_window;
1717: 
1718:   /* These values 9 and 10 are arbitrary,
1719:      just so that there is "something there."
1720:      Correct values are put in in init_xdisp */
1721: 
1722:   XFASTINT (XWINDOW (root_window)->width) = 10;
1723:   XFASTINT (XWINDOW (minibuf_window)->width) = 10;
1724: 
1725:   XFASTINT (XWINDOW (root_window)->height) = 9;
1726:   XFASTINT (XWINDOW (minibuf_window)->top) = 9;
1727:   XFASTINT (XWINDOW (minibuf_window)->height) = 1;
1728: 
1729:   Fshow_buffer (root_window, Fcurrent_buffer ());
1730:   Fshow_buffer (minibuf_window, get_minibuffer (0));
1731: 
1732:   selected_window = root_window;
1733: }
1734: 
1735: syms_of_window ()
1736: {
1737:   Qwindowp = intern ("windowp");
1738:   staticpro (&Qwindowp);
1739: 
1740:   /* Make sure all windows get marked */
1741:   staticpro (&minibuf_window);
1742: 
1743:   DefBoolVar ("pop-up-windows", &pop_up_windows,
1744:     "*Non-nil means display-buffer should make new windows.");
1745:   pop_up_windows = 1;
1746: 
1747:   DefIntVar ("next-screen-context-lines", &next_screen_context_lines,
1748:     "*Number of lines of continuity when scrolling by screenfuls.");
1749:   next_screen_context_lines = 2;
1750: 
1751:   DefIntVar ("split-height-threshold", &split_height_threshold,
1752:     "*display-buffer would prefer to split the largest window if this large.\n\
1753: If there is only one window, it is split regardless of this value.");
1754:   split_height_threshold = 500;
1755: 
1756:   DefIntVar ("window-min-height", &window_min_height,
1757:     "*Delete any window less than this tall (including its mode line).");
1758:   window_min_height = 4;
1759: 
1760:   DefIntVar ("window-min-width", &window_min_width,
1761:     "*Delete any window less than this wide.");
1762:   window_min_width = 10;
1763: 
1764:   defsubr (&Sselected_window);
1765:   defsubr (&Swindowp);
1766:   defsubr (&Spos_visible_in_window_p);
1767:   defsubr (&Swindow_buffer);
1768:   defsubr (&Swindow_height);
1769:   defsubr (&Swindow_width);
1770:   defsubr (&Swindow_hscroll);
1771:   defsubr (&Sset_window_hscroll);
1772:   defsubr (&Swindow_edges);
1773:   defsubr (&Swindow_point);
1774:   defalias (&Swindow_point, "window-dot");
1775:   defsubr (&Swindow_start);
1776:   defsubr (&Sset_window_point);
1777:   defalias (&Sset_window_point, "set-window-dot");
1778:   defsubr (&Sset_window_start);
1779:   defsubr (&Snext_window);
1780:   defsubr (&Sprevious_window);
1781:   defsubr (&Sother_window);
1782:   defsubr (&Sget_lru_window);
1783:   defsubr (&Sget_largest_window);
1784:   defsubr (&Sget_buffer_window);
1785:   defsubr (&Sdelete_other_windows);
1786:   defsubr (&Sdelete_windows_on);
1787:   defsubr (&Sreplace_buffer_in_windows);
1788:   defsubr (&Sdelete_window);
1789:   defsubr (&Sshow_buffer);
1790:   defsubr (&Sselect_window);
1791:   defsubr (&Sdisplay_buffer);
1792:   defsubr (&Ssplit_window);
1793:   defsubr (&Senlarge_window);
1794:   defsubr (&Sshrink_window);
1795:   defsubr (&Sscroll_up);
1796:   defsubr (&Sscroll_down);
1797:   defsubr (&Sscroll_left);
1798:   defsubr (&Sscroll_right);
1799:   defsubr (&Sscroll_other_window);
1800:   defsubr (&Srecenter);
1801:   defsubr (&Smove_to_window_line);
1802:   defsubr (&Ssave_window_excursion);
1803: }
1804: 
1805: keys_of_window ()
1806: {
1807:   defkey (CtlXmap, '1', "delete-other-windows");
1808:   defkey (CtlXmap, '2', "split-window");
1809:   defkey (CtlXmap, '0', "delete-window");
1810:   defkey (CtlXmap, 'o', "other-window");
1811:   defkey (CtlXmap, '^', "enlarge-window");
1812:   defkey (CtlXmap, '<', "scroll-left");
1813:   defkey (CtlXmap, '>', "scroll-right");
1814: 
1815:   defkey (GlobalMap, Ctl ('V'), "scroll-up");
1816:   defkey (ESCmap, Ctl ('V'), "scroll-other-window");
1817:   defkey (ESCmap, 'v', "scroll-down");
1818: 
1819:   defkey (GlobalMap, Ctl('L'), "recenter");
1820:   defkey (ESCmap, 'r', "move-to-window-line");
1821: }

Defined functions

DEFUN defined in line 1679; never used
change_window_height defined in line 1133; used 2 times
count_windows defined in line 1571; used 4 times
decode_window defined in line 169; used 11 times
init_window_once defined in line 1707; used 1 times
keys_of_window defined in line 1805; used 1 times
make_dummy_parent defined in line 949; used 2 times
make_window defined in line 78; used 3 times
replace_window defined in line 365; used 2 times
save_window_restore defined in line 1475; used 2 times
save_window_save_1 defined in line 1615; used 3 times
scroll_command defined in line 1270; used 2 times
set_window_height defined in line 649; used 9 times
set_window_width defined in line 713; used 7 times
syms_of_window defined in line 1735; used 1 times
unshow_buffer defined in line 809; used 2 times
window_height defined in line 1103; used 6 times
window_loop defined in line 494; used 7 times
window_scroll defined in line 1216; used 6 times
window_width defined in line 1111; used 1 times

Defined variables

Qwindowp defined in line 31; used 5 times
minibuf_window defined in line 39; used 25 times
next_screen_context_lines defined in line 64; used 5 times
pop_up_windows defined in line 55; used 3 times
selected_window defined in line 46; used 44 times
sequence_number defined in line 68; used 4 times
split_height_threshold defined in line 60; used 5 times
window_min_height defined in line 50; used 15 times
window_min_width defined in line 51; used 6 times
window_select_count defined in line 770; used 1 times

Defined struct's

save_window_data defined in line 1465; used 12 times
saved_window defined in line 1457; used 6 times

Defined macros

CURBEG defined in line 1123; used 2 times
CURSIZE defined in line 1126; used 2 times
MINSIZE defined in line 1119; used 4 times
SAVE_DATA_SIZE defined in line 1584; used 2 times
Last modified: 1986-03-15
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3946
Valid CSS Valid XHTML 1.0 Strict