(Fprimitive_undo): Bind inhibit-read-only to t if
[bpt/emacs.git] / src / window.c
index ee7a10f..2460e00 100644 (file)
@@ -1,6 +1,6 @@
 /* Window creation, deletion and examination for GNU Emacs.
    Does not include redisplay.
-   Copyright (C) 1985,86,87,93,94,95,96,97,1998 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,93,94,95,96,97,1998,2000 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -79,6 +79,7 @@ static void decode_next_window_args P_ ((Lisp_Object *, Lisp_Object *,
 static int foreach_window_1 P_ ((struct window *,
                                 int (* fn) (struct window *, void *),
                                 void *));
+static Lisp_Object window_list_1 P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
 
 /* This is the window in which the terminal's cursor should
    be left when nothing is being done with it.  This must
@@ -290,53 +291,16 @@ DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1,
      Lisp_Object window;
 {
   struct window *w = decode_window (window);
-  return (MINI_WINDOW_P (w) ? Qt : Qnil);
-}
-
-
-/* Return true if POS is fully visible in the window W.  If W's end
-   position is not known, then return false.  */
-
-static int
-pos_fully_visible_in_window_p (pos, w)
-     int pos;
-     struct window *w;
-{
-  struct glyph_row *first_row = &w->desired_matrix->rows[0];
-  struct glyph_row *last_row;
-
-  if (pos < first_row->start.pos.charpos)
-    /* POS is before the beginning of W.  */
-    return 0;
-  else if (pos < first_row->end.pos.charpos)
-    /* POS is on the first row of W, so see if that row is fully visible.  */
-    return !MATRIX_ROW_PARTIALLY_VISIBLE_P (first_row);
-
-  if (NILP (w->window_end_valid))
-    /* We can't determine where the end is, so we don't know.  */
-    return 0;
-
-  last_row = &w->desired_matrix->rows[XFASTINT (w->window_end_vpos)];
-
-  if (pos < last_row->start.pos.charpos)
-    /* POS is somewhere in the middle of the window, not on the first or
-       last row, so it must be visible.  */
-    return 1;
-  else if (pos >= last_row->end.pos.charpos)
-    /* POS is after the end of W.  */
-    return 0;
-  else
-    /* POS is on the last row of W, so see if that row is fully visible.  */
-    return !MATRIX_ROW_PARTIALLY_VISIBLE_P (last_row);
+  return MINI_WINDOW_P (w) ? Qt : Qnil;
 }
 
 
 DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
   Spos_visible_in_window_p, 0, 3, 0,
   "Return t if position POS is currently on the frame in WINDOW.\n\
-Returns nil if that position is scrolled vertically out of view.\n\
+Return nil if that position is scrolled vertically out of view.\n\
 If FULLY is non-nil, then only return t when POS is completely visible.\n\
-POS defaults to point; WINDOW, to the selected window.")
+POS defaults to point in WINDOW; WINDOW defaults to the selected window.")
   (pos, window, fully)
      Lisp_Object pos, window, fully;
 {
@@ -345,34 +309,40 @@ POS defaults to point; WINDOW, to the selected window.")
   register struct buffer *buf;
   struct text_pos top;
   Lisp_Object in_window;
+  int fully_p;
 
-  if (NILP (pos))
-    posint = PT;
-  else
+  w = decode_window (window);
+  buf = XBUFFER (w->buffer);
+  SET_TEXT_POS_FROM_MARKER (top, w->start);
+
+  if (!NILP (pos))
     {
       CHECK_NUMBER_COERCE_MARKER (pos, 0);
       posint = XINT (pos);
     }
+  else if (w == XWINDOW (selected_window))
+    posint = PT;
+  else
+    posint = XMARKER (w->pointm)->charpos;
 
-  w = decode_window (window);
-  buf = XBUFFER (w->buffer);
-  SET_TEXT_POS_FROM_MARKER (top, w->start);
-
-  /* If position above window, it's not visible.  */
+  /* If position is above window start, it's not visible.  */
   if (posint < CHARPOS (top))
     in_window = Qnil;
   else if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
           && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf)
           && posint < BUF_Z (buf) - XFASTINT (w->window_end_pos))
-    /* If frame is up to date, and POSINT is < window end pos, use
-       that info.  This doesn't work for POSINT == end pos, because
-       the window end pos is actually the position _after_ the last
-       char in the window.  */
     {
-      if (NILP (fully) || pos_fully_visible_in_window_p (posint, w))
-       in_window = Qt;
+      /* If frame is up-to-date, and POSINT is < window end pos, use
+        that info.  This doesn't work for POSINT == end pos, because
+        the window end pos is actually the position _after_ the last
+        char in the window.  */
+      if (!NILP (fully))
+       {
+         pos_visible_p (w, posint, &fully_p, !NILP (fully));
+         in_window = fully_p ? Qt : Qnil;
+       }
       else
-       in_window = Qnil;
+       in_window = Qt;
     }
   else if (posint > BUF_ZV (buf))
     in_window = Qnil;
@@ -381,26 +351,15 @@ POS defaults to point; WINDOW, to the selected window.")
     in_window = Qnil;
   else
     {
-      struct it it;
-      start_display (&it, w, top);
-      move_it_to (&it, posint, 0, it.last_visible_y, -1,
-                 MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
-      if (IT_CHARPOS (it) == posint)
-       {
-         if (NILP (fully))
-           in_window = Qt;
-         else
-           {
-             struct glyph_row *pos_row = &w->desired_matrix->rows[it.vpos];
-             return MATRIX_ROW_PARTIALLY_VISIBLE_P(pos_row) ? Qnil : Qt;
-           }
-       }
+      if (pos_visible_p (w, posint, &fully_p, !NILP (fully)))
+       in_window = NILP (fully) || fully_p ? Qt : Qnil;
       else
        in_window = Qnil;
     }
 
   return in_window;
 }
+
 \f
 static struct window *
 decode_window (window)
@@ -536,6 +495,11 @@ coordinates_in_window (w, x, y)
   int left_x, right_x, top_y, bottom_y;
   int flags_area_width = FRAME_LEFT_FLAGS_AREA_WIDTH (f);
 
+  /* Let's make this a global enum later, instead of using numbers
+     everywhere.  */
+  enum {ON_NOTHING, ON_TEXT, ON_MODE_LINE, ON_VERTICAL_BORDER,
+       ON_HEADER_LINE, ON_LEFT_FRINGE, ON_RIGHT_FRINGE};
+
   /* In what's below, we subtract 1 when computing right_x because we
      want the rightmost pixel, which is given by left_pixel+width-1.  */
   if (w->pseudo_window_p)
@@ -555,6 +519,7 @@ coordinates_in_window (w, x, y)
       bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
     }
 
+  /* Completely outside anything interesting?  */
   if (*y < top_y
       || *y >= bottom_y
       || *x < (left_x
@@ -562,42 +527,83 @@ coordinates_in_window (w, x, y)
               - (FRAME_LEFT_SCROLL_BAR_WIDTH (f)
                  * CANON_X_UNIT (f)))
       || *x > right_x + flags_area_width)
-    /* Completely outside anything interesting.  */
-    return 0;
-  else if (WINDOW_WANTS_MODELINE_P (w)
-          && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
-    /* On the mode line.  */
-    return 2;
-  else if (WINDOW_WANTS_HEADER_LINE_P (w)
-          && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
-    /* On the top line.  */
-    return 4;
-  /* Need to say "*x > right_x" rather than >=, since on character
-     terminals, the vertical line's x coordinate is right_x.  */
-  else if (*x < left_x || *x > right_x)
+    return ON_NOTHING;
+  
+  /* On the mode line or header line?  If it's near the start of
+     the mode or header line of window that's has a horizontal
+     sibling, say it's on the vertical line.  That's to be able
+     to resize windows horizontally in case we're using toolkit
+     scroll bars.  */
+  
+  if (WINDOW_WANTS_MODELINE_P (w)
+      && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
+    {
+      if (!WINDOW_RIGHTMOST_P (w)
+         && (abs (*x - ((XFASTINT (w->left) + XFASTINT (w->width))
+                        * CANON_X_UNIT (f)))
+             < CANON_X_UNIT (f) / 2))
+       return ON_VERTICAL_BORDER;
+      return ON_MODE_LINE;
+    }
+  
+  if (WINDOW_WANTS_HEADER_LINE_P (w)
+      && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
+    {
+      if (!WINDOW_RIGHTMOST_P (w)
+         && (abs (*x - ((XFASTINT (w->left) + XFASTINT (w->width))
+                        * CANON_X_UNIT (f)))
+             < CANON_X_UNIT (f) / 2))
+       return ON_VERTICAL_BORDER;
+      return ON_HEADER_LINE;
+    }
+
+  if (FRAME_WINDOW_P (f))
     {
-      /* Other lines than the mode line don't include flags areas and
-        scroll bars on the left.  */
+      if (!w->pseudo_window_p
+         && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)
+         && !WINDOW_RIGHTMOST_P (w)
+         && (abs (*x - right_x - flags_area_width) < CANON_X_UNIT (f) / 2))
+       return ON_VERTICAL_BORDER;
+
+      if (*x < left_x || *x > right_x)
+       {
+         /* Other lines than the mode line don't include flags areas and
+            scroll bars on the left.  */
       
-      /* Convert X and Y to window-relative pixel coordinates.  */
-      *x -= left_x;
-      *y -= top_y;
-      return *x < left_x ? 5 : 6;
+         /* Convert X and Y to window-relative pixel coordinates.  */
+         *x -= left_x;
+         *y -= top_y;
+         return *x < left_x ? ON_LEFT_FRINGE : ON_RIGHT_FRINGE;
+       }
     }
-  /* Here, too, "*x > right_x" is because of character terminals.  */
-  else if (!w->pseudo_window_p
-          && !WINDOW_RIGHTMOST_P (w)
-          && *x > right_x - CANON_X_UNIT (f))
-    /* On the border on the right side of the window?  Assume that
-       this area begins at RIGHT_X minus a canonical char width.  */
-    return 3;
   else
     {
-      /* Convert X and Y to window-relative pixel coordinates.  */
-      *x -= left_x;
-      *y -= top_y;
-      return 1;
+      /* Need to say "*x > right_x" rather than >=, since on character
+        terminals, the vertical line's x coordinate is right_x.  */
+      if (*x < left_x || *x > right_x)
+       {
+         /* Other lines than the mode line don't include flags areas and
+            scroll bars on the left.  */
+      
+         /* Convert X and Y to window-relative pixel coordinates.  */
+         *x -= left_x;
+         *y -= top_y;
+         return *x < left_x ? ON_LEFT_FRINGE : ON_RIGHT_FRINGE;
+       }
+  
+      /* Here, too, "*x > right_x" is because of character terminals.  */
+      if (!w->pseudo_window_p
+         && !WINDOW_RIGHTMOST_P (w)
+         && *x > right_x - CANON_X_UNIT (f))
+       /* On the border on the right side of the window?  Assume that
+          this area begins at RIGHT_X minus a canonical char width.  */
+       return ON_VERTICAL_BORDER;
     }
+  
+  /* Convert X and Y to window-relative pixel coordinates.  */
+  *x -= left_x;
+  *y -= top_y;
+  return ON_TEXT;
 }
 
 DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
@@ -1591,9 +1597,35 @@ argument ALL_FRAMES is non-nil, cycle through all frames.")
 
 
 DEFUN ("window-list", Fwindow_list, Swindow_list, 0, 3, 0,
-  "Return a list of windows in canonical ordering.\n\
-Arguments are like for `next-window'.")
-  (window, minibuf, all_frames)
+  "Return a list of windows on FRAME, starting with WINDOW.\n\
+FRAME nil or omitted means use the selected frame.\n\
+WINDOW nil or omitted means use the selected window.\n\
+MINIBUF t means include the minibuffer window, even if it isn't active.\n\
+MINIBUF nil or omitted means include the minibuffer window only\n\
+if it's active.\n\
+MINIBUF neither nil nor t means never include the minibuffer window.")
+  (frame, minibuf, window)
+     Lisp_Object frame, minibuf, window;
+{
+  Lisp_Object list;
+
+  if (NILP (window))
+    window = selected_window;
+  if (NILP (frame))
+    frame = selected_frame;
+
+  if (!EQ (frame, XWINDOW (window)->frame))
+    error ("Window is on a different frame");
+
+  return window_list_1 (window, minibuf, frame);
+}
+
+
+/* Return a list of windows in canonical ordering.  Arguments are like
+   for `next-window'.  */
+
+static Lisp_Object
+window_list_1 (window, minibuf, all_frames)
      Lisp_Object window, minibuf, all_frames;
 {
   Lisp_Object tail, list;
@@ -1679,7 +1711,7 @@ window_loop (type, obj, mini, frames)
      We can't just wait until we hit the first window again, because
      it might be deleted.  */
 
-  windows = Fwindow_list (window, mini ? Qt : Qnil, frame_arg);
+  windows = window_list_1 (window, mini ? Qt : Qnil, frame_arg);
   GCPRO1 (windows);
   best_window = Qnil;
 
@@ -2314,18 +2346,19 @@ size_window (window, size, width_p, nodelete_p)
   int old_size, min_size;
 
   check_min_window_sizes ();
+  size = max (0, size);
   
   /* If the window has been "too small" at one point,
      don't delete it for being "too small" in the future.
      Preserve it as long as that is at all possible.  */
   if (width_p)
     {
-      old_size = XFASTINT (w->width);
+      old_size = XINT (w->width);
       min_size = window_min_width;
     }
   else
     {
-      old_size = XFASTINT (w->height);
+      old_size = XINT (w->height);
       min_size = window_min_height;
     }
   
@@ -2350,22 +2383,22 @@ size_window (window, size, width_p, nodelete_p)
     }
 
   /* Set redisplay hints.  */
-  XSETFASTINT (w->last_modified, 0);
-  XSETFASTINT (w->last_overlay_modified, 0);
+  w->last_modified = make_number (0);
+  w->last_overlay_modified = make_number (0);
   windows_or_buffers_changed++;
-  FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
+  FRAME_WINDOW_SIZES_CHANGED (XFRAME (w->frame)) = 1;
 
   if (width_p)
     {
       sideward = &w->vchild;
       forward = &w->hchild;
-      XSETFASTINT (w->width, size);
+      w->width = make_number (size);
     }
   else
     {
       sideward = &w->hchild;
       forward = &w->vchild;
-      XSETFASTINT (w->height, size);
+      w->height = make_number (size);
     }
 
   if (!NILP (*sideward))
@@ -2384,18 +2417,22 @@ size_window (window, size, width_p, nodelete_p)
     {
       int fixed_size, each, extra, n;
       int resize_fixed_p, nfixed;
-      int last_pos, first_pos, nchildren;
+      int last_pos, first_pos, nchildren, total;
 
       /* Determine the fixed-size portion of the this window, and the
         number of child windows.  */
-      fixed_size = nchildren = nfixed = 0;
+      fixed_size = nchildren = nfixed = total = 0;
       for (child = *forward; !NILP (child); child = c->next, ++nchildren)
        {
+         int child_size;
+         
          c = XWINDOW (child);
+         child_size = width_p ? XINT (c->width) : XINT (c->height);
+         total += child_size;
+         
          if (window_fixed_size_p (c, width_p, 0))
            {
-             fixed_size += (width_p
-                            ? XFASTINT (c->width) : XFASTINT (c->height));
+             fixed_size += child_size;
              ++nfixed;
            }
        }
@@ -2408,11 +2445,11 @@ size_window (window, size, width_p, nodelete_p)
       /* Compute how many lines/columns to add to each child.  The
         value of extra takes care of rounding errors.  */
       n = resize_fixed_p ? nchildren : nchildren - nfixed;
-      each = (size - old_size) / n;
-      extra = (size - old_size) - n * each;
+      each = (size - total) / n;
+      extra = (size - total) - n * each;
 
       /* Compute new children heights and edge positions.  */
-      first_pos = width_p ? XFASTINT (w->left) : XFASTINT (w->top);
+      first_pos = width_p ? XINT (w->left) : XINT (w->top);
       last_pos = first_pos;
       for (child = *forward; !NILP (child); child = c->next)
        {
@@ -2455,7 +2492,7 @@ size_window (window, size, width_p, nodelete_p)
          {
            int child_size;
            c = XWINDOW (child);
-           child_size = width_p ? XFASTINT (c->width) : XFASTINT (c->height);
+           child_size = width_p ? XINT (c->width) : XINT (c->height);
            size_window (child, child_size, width_p, 0);
          }
     }
@@ -2805,7 +2842,7 @@ If FRAME is t, search all frames.\n\
 If FRAME is a frame, search only that frame.\n\
 If FRAME is nil, search only the selected frame\n\
  (actually the last nonminibuffer frame),\n\
- unless `pop-up-frames' or `display-reuse-frames' is non-nil,\n\
+ unless `pop-up-frames' or `display-buffer-reuse-frames' is non-nil,\n\
  which means search visible and iconified frames.")
   (buffer, not_this_window, frame)
      register Lisp_Object buffer, not_this_window, frame;
@@ -3842,7 +3879,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
   /* If PT is not visible in WINDOW, move back one half of
      the screen.  */
   XSETFASTINT (tem, PT);
-  tem = Fpos_visible_in_window_p (tem, window, Qt);
+  tem = Fpos_visible_in_window_p (tem, window, Qnil);
   if (NILP (tem))
     {
       /* Move backward half the height of the window.  Performance note:
@@ -3986,7 +4023,7 @@ window_scroll_line_based (window, n, whole, noerror)
   original_vpos = posit.vpos;
 
   XSETFASTINT (tem, PT);
-  tem = Fpos_visible_in_window_p (tem, window, Qt);
+  tem = Fpos_visible_in_window_p (tem, window, Qnil);
 
   if (NILP (tem))
     {
@@ -4361,19 +4398,36 @@ displayed_window_lines (w)
   struct it it;
   struct text_pos start;
   int height = window_box_height (w);
+  struct buffer *old_buffer;
+  int bottom_y;
+
+  if (XBUFFER (w->buffer) != current_buffer)
+    {
+      old_buffer = current_buffer;
+      set_buffer_internal (XBUFFER (w->buffer));
+    }
+  else
+    old_buffer = NULL;
 
   SET_TEXT_POS_FROM_MARKER (start, w->start);
   start_display (&it, w, start);
   move_it_vertically (&it, height);
 
+  if (old_buffer)
+    set_buffer_internal (old_buffer);
+
   /* Add in empty lines at the bottom of the window.  */
-  if (it.current_y < height)
+  bottom_y = it.current_y + it.max_ascent + it.max_descent;
+  if (bottom_y < height)
     {
       struct frame *f = XFRAME (w->frame);
-      int rest = height - it.current_y;
+      int rest = height - bottom_y;
       int lines = (rest + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
       it.vpos += lines;
     }
+  else if (it.current_y < height && bottom_y > height)
+    /* Partially visible line at the bottom.  */
+    ++it.vpos;
   
   return it.vpos;
 }
@@ -4458,8 +4512,9 @@ struct saved_window
     Lisp_Object parent, prev;
     Lisp_Object start_at_line_beg;
     Lisp_Object display_table;
+    Lisp_Object orig_top, orig_height;
   };
-#define SAVED_WINDOW_VECTOR_SIZE 14 /* Arg to Fmake_vector */
+#define SAVED_WINDOW_VECTOR_SIZE 16 /* Arg to Fmake_vector */
 
 #define SAVED_WINDOW_N(swv,n) \
   ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
@@ -4521,7 +4576,6 @@ the return value is nil.  Otherwise the value is t.")
     {
       if (XBUFFER (new_current_buffer) == current_buffer)
        old_point = PT;
-
     }
 
   frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
@@ -4536,7 +4590,7 @@ the return value is nil.  Otherwise the value is t.")
       struct window *root_window;
       struct window **leaf_windows;
       int n_leaf_windows;
-      int k, i;
+      int k, i, n;
 
       /* If the frame has been resized since this window configuration was
         made, we change the frame to the size specified in the
@@ -4652,6 +4706,8 @@ the return value is nil.  Otherwise the value is t.")
          w->height = p->height;
          w->hscroll = p->hscroll;
          w->display_table = p->display_table;
+         w->orig_top = p->orig_top;
+         w->orig_height = p->orig_height;
          XSETFASTINT (w->last_modified, 0);
          XSETFASTINT (w->last_overlay_modified, 0);
 
@@ -4743,15 +4799,24 @@ the return value is nil.  Otherwise the value is t.")
 #endif
 
       /* Now, free glyph matrices in windows that were not reused.  */
-      for (i = 0; i < n_leaf_windows; ++i)
-       if (NILP (leaf_windows[i]->buffer))
-         {
-           /* Assert it's not reused as a combination.  */
-           xassert (NILP (leaf_windows[i]->hchild) 
-                    && NILP (leaf_windows[i]->vchild));
-           free_window_matrices (leaf_windows[i]);
-           SET_FRAME_GARBAGED (f);
-         }
+      for (i = n = 0; i < n_leaf_windows; ++i)
+       {
+         if (NILP (leaf_windows[i]->buffer))
+           {
+             /* Assert it's not reused as a combination.  */
+             xassert (NILP (leaf_windows[i]->hchild) 
+                      && NILP (leaf_windows[i]->vchild));
+             free_window_matrices (leaf_windows[i]);
+             SET_FRAME_GARBAGED (f);
+           }
+         else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
+           ++n;
+       }
+
+      /* If more than one window shows the new and old current buffer,
+        don't try to preserve point in that buffer.  */
+      if (old_point > 0 && n > 1)
+       old_point = -1;
       
       adjust_glyphs (f);
 
@@ -4908,6 +4973,8 @@ save_window_save (window, vector, i)
       p->height = w->height;
       p->hscroll = w->hscroll;
       p->display_table = w->display_table;
+      p->orig_top = w->orig_top;
+      p->orig_height = w->orig_height;
       if (!NILP (w->buffer))
        {
          /* Save w's value of point in the window configuration.
@@ -5005,8 +5072,7 @@ redirection (see `redirect-frame-focus').")
   for (i = 0; i < n_windows; i++)
     XVECTOR (tem)->contents[i]
       = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
-  save_window_save (FRAME_ROOT_WINDOW (f),
-                   XVECTOR (tem), 0);
+  save_window_save (FRAME_ROOT_WINDOW (f), XVECTOR (tem), 0);
   XSETWINDOW_CONFIGURATION (tem, data);
   return (tem);
 }