]> code.delx.au - gnu-emacs/blobdiff - src/window.c
Put doc strings in comments.
[gnu-emacs] / src / window.c
index b02cc6b7969c66cf494691dcf9dbb77f4e553a85..4c629113d9d4a74dd51ef36d532568e46513c115 100644 (file)
@@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA.  */
 #include "lisp.h"
 #include "buffer.h"
 #include "keyboard.h"
+#include "keymap.h"
 #include "frame.h"
 #include "window.h"
 #include "commands.h"
@@ -69,6 +70,7 @@ Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
 Lisp_Object Qwindow_size_fixed, Qleft_fringe, Qright_fringe;
 extern Lisp_Object Qheight, Qwidth;
 
+static int displayed_window_lines P_ ((struct window *));
 static struct window *decode_window P_ ((Lisp_Object));
 static Lisp_Object select_window_1 P_ ((Lisp_Object, int));
 static int count_windows P_ ((struct window *));
@@ -220,8 +222,6 @@ Lisp_Object Vscroll_preserve_screen_position;
 static int inhibit_frame_unsplittable;
 #endif /* 0 */
 
-#define min(a, b) ((a) < (b) ? (a) : (b))
-
 extern int scroll_margin;
 
 extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
@@ -1660,7 +1660,7 @@ argument ALL_FRAMES is non-nil, cycle through all frames.")
     window = Fnext_window (window, Qnil, all_frames);
   for (; i < 0; ++i)
     window = Fprevious_window (window, Qnil, all_frames);
-  
+
   Fselect_window (window);
   return Qnil;
 }
@@ -1854,8 +1854,6 @@ window_loop (type, obj, mini, frames)
                       display there.  */
                    Lisp_Object buffer;
                    buffer = Fother_buffer (obj, Qnil, w->frame);
-                   if (NILP (buffer))
-                     buffer = Fget_buffer_create (build_string ("*scratch*"));
                    Fset_window_buffer (window, buffer);
                    if (EQ (window, selected_window))
                      Fset_buffer (w->buffer);
@@ -1891,8 +1889,6 @@ window_loop (type, obj, mini, frames)
                
                /* Find another buffer to show in this window.  */
                buffer = Fother_buffer (obj, Qnil, w->frame);
-               if (NILP (buffer))
-                 buffer = Fget_buffer_create (build_string ("*scratch*"));
                
                /* If this window is dedicated, and in a frame of its own,
                   kill the frame.  */
@@ -2733,9 +2729,7 @@ select_window_1 (window, recordflag)
   CHECK_LIVE_WINDOW (window, 0);
 
   w = XWINDOW (window);
-
-  if (NILP (w->buffer))
-    error ("Trying to select deleted window or non-leaf window");
+  w->frozen_window_start_p = 0;
 
   XSETFASTINT (w->use_time, ++window_select_count);
   if (EQ (window, selected_window))
@@ -3855,7 +3849,7 @@ mark_window_cursors_off (w)
 }
 
 
-/* Return number of lines of text (not counting mode line) in W.  */
+/* Return number of lines of text (not counting mode lines) in W.  */
 
 int
 window_internal_height (w)
@@ -3863,13 +3857,19 @@ window_internal_height (w)
 {
   int ht = XFASTINT (w->height);
 
-  if (MINI_WINDOW_P (w))
-    return ht;
-
-  if (!NILP (w->parent) || !NILP (w->vchild) || !NILP (w->hchild)
-      || !NILP (w->next) || !NILP (w->prev)
-      || FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (w))))
-    return ht - 1;
+  if (!MINI_WINDOW_P (w))
+    {
+      if (!NILP (w->parent)
+         || !NILP (w->vchild)
+         || !NILP (w->hchild)
+         || !NILP (w->next)
+         || !NILP (w->prev)
+         || WINDOW_WANTS_MODELINE_P (w))
+       --ht;
+
+      if (WINDOW_WANTS_HEADER_LINE_P (w))
+       --ht;
+    }
 
   return ht;
 }
@@ -3908,7 +3908,7 @@ window_internal_width (w)
  ***********************************************************************/
 
 /* Scroll contents of window WINDOW up.  If WHOLE is non-zero, scroll
-   one screen-full, which is defined as the height of the window minus
+   N screen-fulls, which is defined as the height of the window minus
    next_screen_context_lines.  If WHOLE is zero, scroll up N lines
    instead.  Negative values of N mean scroll down.  NOERROR non-zero
    means don't signal an error if we try to move over BEGV or ZV,
@@ -3953,8 +3953,10 @@ window_scroll_pixel_based (window, n, whole, noerror)
   SET_TEXT_POS_FROM_MARKER (start, w->start);
   
   /* If PT is not visible in WINDOW, move back one half of
-     the screen.  */
-  tem = Fpos_visible_in_window_p (make_number (PT), window, Qnil);
+     the screen.  Allow PT to be partially visible, otherwise
+     something like (scroll-down 1) with PT in the line before
+     the partially visible one would recenter. */
+  tem = Fpos_visible_in_window_p (make_number (PT), window, Qt);
   if (NILP (tem))
     {
       /* Move backward half the height of the window.  Performance note:
@@ -3962,7 +3964,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
         results for variable height lines.  */
       init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
       it.current_y = it.last_visible_y;
-      move_it_vertically (&it, -it.last_visible_y / 2);
+      move_it_vertically (&it, - window_box_height (w) / 2);
       
       /* The function move_iterator_vertically may move over more than
         the specified y-distance.  If it->w is small, e.g. a
@@ -3995,10 +3997,9 @@ window_scroll_pixel_based (window, n, whole, noerror)
   start_display (&it, w, start);
   if (whole)
     {
-      int screen_full = (it.last_visible_y
+      int screen_full = (window_box_height (w)
                         - next_screen_context_lines * CANON_Y_UNIT (it.f));
-      int direction = n < 0 ? -1 : 1;
-      int dy = direction * screen_full;
+      int dy = n * screen_full;
 
       /* Note that move_it_vertically always moves the iterator to the
          start of a line.  So, if the last line doesn't have a newline,
@@ -4142,6 +4143,11 @@ window_scroll_line_based (window, n, whole, noerror)
   struct position posit;
   int original_vpos;
 
+  /* If scrolling screen-fulls, compute the number of lines to
+     scroll from the window's height.  */
+  if (whole)
+    n *= max (1, ht - next_screen_context_lines);
+
   startpos = marker_position (w->start);
 
   posit = *compute_motion (startpos, 0, 0, 0,
@@ -4273,8 +4279,7 @@ scroll_command (n, direction)
      Lisp_Object n;
      int direction;
 {
-  register int defalt;
-  int count = specpdl_ptr - specpdl;
+  int count = BINDING_STACK_SIZE ();
 
   xassert (abs (direction) == 1);
 
@@ -4289,14 +4294,10 @@ scroll_command (n, direction)
       ++windows_or_buffers_changed;
     }
 
-  defalt = (window_internal_height (XWINDOW (selected_window))
-           - next_screen_context_lines);
-  defalt = direction * (defalt < 1 ? 1 : defalt);
-
   if (NILP (n))
-    window_scroll (selected_window, defalt, 1, 0);
+    window_scroll (selected_window, direction, 1, 0);
   else if (EQ (n, Qminus))
-    window_scroll (selected_window, - defalt, 1, 0);
+    window_scroll (selected_window, -direction, 1, 0);
   else
     {
       n = Fprefix_numeric_value (n);
@@ -4388,18 +4389,14 @@ specifies the window to scroll.\n\
 If `other-window-scroll-buffer' is non-nil, scroll the window\n\
 showing that buffer, popping the buffer up if necessary.")
   (arg)
-     register Lisp_Object arg;
+     Lisp_Object arg;
 {
-  register Lisp_Object window;
-  register int defalt;
-  register struct window *w;
-  register int count = specpdl_ptr - specpdl;
+  Lisp_Object window;
+  struct window *w;
+  int count = BINDING_STACK_SIZE ();
 
   window = Fother_window_for_scrolling ();
-
   w = XWINDOW (window);
-  defalt = window_internal_height (w) - next_screen_context_lines;
-  if (defalt < 1) defalt = 1;
 
   /* Don't screw up if window_scroll gets an error.  */
   record_unwind_protect (save_excursion_restore, save_excursion_save ());
@@ -4409,9 +4406,9 @@ showing that buffer, popping the buffer up if necessary.")
   SET_PT (marker_position (w->pointm));
 
   if (NILP (arg))
-    window_scroll (window, defalt, 1, 1);
+    window_scroll (window, 1, 1, 1);
   else if (EQ (arg, Qminus))
-    window_scroll (window, -defalt, 1, 1);
+    window_scroll (window, -1, 1, 1);
   else
     {
       if (CONSP (arg))
@@ -4495,7 +4492,16 @@ displayed_window_lines (w)
   else
     old_buffer = NULL;
 
-  SET_TEXT_POS_FROM_MARKER (start, w->start);
+  /* In case W->start is out of the accessible range, do something
+     reasonable.  This happens in Info mode when Info-scroll-down
+     calls (recenter -1) while W->start is 1.  */
+  if (XMARKER (w->start)->charpos < BEGV)
+    SET_TEXT_POS (start, BEGV, BEGV_BYTE);
+  else if (XMARKER (w->start)->charpos > ZV)
+    SET_TEXT_POS (start, ZV, ZV_BYTE);
+  else
+    SET_TEXT_POS_FROM_MARKER (start, w->start);
+
   start_display (&it, w, start);
   move_it_vertically (&it, height);
   bottom_y = line_bottom_y (&it);
@@ -4555,34 +4561,70 @@ and redisplay normally--don't erase and redraw the frame.")
 
   set_buffer_internal (buf);
 
-  /* Handle centering on a gfaphical frame specially.  Such frames can
+  /* Handle centering on a graphical frame specially.  Such frames can
      have variable-height lines and centering point on the basis of
      line counts would lead to strange effects.  */
-  if (center_p && FRAME_WINDOW_P (XFRAME (w->frame)))
+  if (FRAME_WINDOW_P (XFRAME (w->frame)))
     {
-      struct it it;
-      struct text_pos pt;
-      
-      SET_TEXT_POS (pt, PT, PT_BYTE);
-      start_display (&it, w, pt);
-      move_it_vertically (&it, - it.last_visible_y / 2);
-      charpos = IT_CHARPOS (it);
-      bytepos = IT_BYTEPOS (it);
-    }
-  else
-    {
-      struct position pos;
-      
       if (center_p)
        {
-         int ht = displayed_window_lines (w);
-         arg = make_number (ht / 2);
+         struct it it;
+         struct text_pos pt;
+         
+         SET_TEXT_POS (pt, PT, PT_BYTE);
+         start_display (&it, w, pt);
+         move_it_vertically (&it, - window_box_height (w) / 2);
+         charpos = IT_CHARPOS (it);
+         bytepos = IT_BYTEPOS (it);
        }
       else if (XINT (arg) < 0)
        {
-         int ht = displayed_window_lines (w);
-         XSETINT (arg, XINT (arg) + ht);
+         struct it it;
+         struct text_pos pt;
+         int y0, y1, h, nlines;
+         
+         SET_TEXT_POS (pt, PT, PT_BYTE);
+         start_display (&it, w, pt);
+         y0 = it.current_y;
+
+         /* The amount of pixels we have to move back is the window
+            height minus what's displayed in the line containing PT,
+            and the lines below.  */
+         nlines = - XINT (arg) - 1;
+         move_it_by_lines (&it, nlines, 1);
+
+         y1 = it.current_y - y0;
+         h = line_bottom_y (&it) - y1;
+
+         /* If we can't move down NLINES lines because we hit
+            the end of the buffer, count in some empty lines.  */
+         if (it.vpos < nlines)
+           y1 += (nlines - it.vpos) * CANON_Y_UNIT (it.f);
+         
+         y0 = it.last_visible_y - y1 - h;
+         
+         start_display (&it, w, pt);
+         move_it_vertically (&it, - y0);
+         charpos = IT_CHARPOS (it);
+         bytepos = IT_BYTEPOS (it);
+       }
+      else
+       {
+         struct position pos;
+         pos = *vmotion (PT, - XINT (arg), w);
+         charpos = pos.bufpos;
+         bytepos = pos.bytepos;
        }
+    }
+  else
+    {
+      struct position pos;
+      int ht = window_internal_height (w);
+
+      if (center_p)
+       arg = make_number (ht / 2);
+      else if (XINT (arg) < 0)
+       arg = make_number (XINT (arg) + ht);
       
       pos = *vmotion (PT, - XINT (arg), w);
       charpos = pos.bufpos;
@@ -4970,7 +5012,7 @@ the return value is nil.  Otherwise the value is t.")
          when the frame's old selected window has been deleted.  */
       if (f != selected_frame && FRAME_WINDOW_P (f))
        do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
-                        Qnil, 0);
+                        0, 0);
 #endif
 
       /* Set the screen height to the value it had before this function.  */
@@ -5018,7 +5060,7 @@ the return value is nil.  Otherwise the value is t.")
         Fselect_window above totally superfluous; it still sets f's
         selected window.  */
       if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
-       do_switch_frame (data->selected_frame, Qnil, 0);
+       do_switch_frame (data->selected_frame, 0, 0);
 
       if (! NILP (Vwindow_configuration_change_hook)
          && ! NILP (Vrun_hooks))
@@ -5460,7 +5502,7 @@ foreach_window_1 (w, fn, user_data)
 }
 
 
-/* Freeze or unfreeze the window start of W if unless it is a
+/* Freeze or unfreeze the window start of W unless it is a
    mini-window or the selected window.  FREEZE_P non-null means freeze
    the window start.  */