]> code.delx.au - gnu-emacs/blobdiff - src/window.c
Put doc strings in comments.
[gnu-emacs] / src / window.c
index 769aa56a38d09f872478841162e9b4319b550199..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;
@@ -247,14 +247,8 @@ make_window ()
 {
   Lisp_Object val;
   register struct window *p;
-  register struct Lisp_Vector *vec;
-  int i;
 
-  vec = allocate_vectorlike ((EMACS_INT) VECSIZE (struct window));
-  for (i = 0; i < VECSIZE (struct window); i++)
-    vec->contents[i] = Qnil;
-  vec->size = VECSIZE (struct window);
-  p = (struct window *) vec;
+  p = allocate_window ();
   XSETFASTINT (p->sequence_number, ++sequence_number);
   XSETFASTINT (p->left, 0);
   XSETFASTINT (p->top, 0);
@@ -526,6 +520,9 @@ coordinates_in_window (w, x, y)
   int ux = CANON_X_UNIT (f), uy = CANON_Y_UNIT (f);
   int x0 = XFASTINT (w->left) * ux;
   int x1 = x0 + XFASTINT (w->width) * ux;
+  /* The width of the area where the vertical line can be dragged.
+     (Between mode lines for instance.  */
+  int grabbable_width = ux;
 
   if (*x < x0 || *x >= x1)
     return ON_NOTHING;
@@ -567,10 +564,10 @@ coordinates_in_window (w, x, y)
       
       if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
        {
-         if (abs (*x - x0) < ux / 2)
+         if (abs (*x - x0) < grabbable_width)
            part = ON_VERTICAL_BORDER;
        }
-      else if (!WINDOW_RIGHTMOST_P (w) && abs (*x - x1) < ux / 2)
+      else if (!WINDOW_RIGHTMOST_P (w) && abs (*x - x1) < grabbable_width)
        part = ON_VERTICAL_BORDER;
     }
   else if (WINDOW_WANTS_HEADER_LINE_P (w)
@@ -581,10 +578,10 @@ coordinates_in_window (w, x, y)
       
       if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
        {
-         if (abs (*x - x0) < ux / 2)
+         if (abs (*x - x0) < grabbable_width)
            part = ON_VERTICAL_BORDER;
        }
-      else if (!WINDOW_RIGHTMOST_P (w) && abs (*x - x1) < ux / 2)
+      else if (!WINDOW_RIGHTMOST_P (w) && abs (*x - x1) < grabbable_width)
        part = ON_VERTICAL_BORDER;
     }
   /* Outside anything interesting?  */
@@ -604,7 +601,7 @@ coordinates_in_window (w, x, y)
       if (!w->pseudo_window_p
          && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)
          && !WINDOW_RIGHTMOST_P (w)
-         && (abs (*x - right_x - flags_area_width) < ux / 2))
+         && (abs (*x - right_x - flags_area_width) < grabbable_width))
        {
          part = ON_VERTICAL_BORDER;
        }
@@ -909,6 +906,7 @@ if it isn't already recorded.")
     {
       struct text_pos startp;
       struct it it;
+      struct buffer *old_buffer = NULL, *b = XBUFFER (buf);
 
       /* In case W->start is out of the range, use something
          reasonable.  This situation occured when loading a file with
@@ -924,10 +922,20 @@ if it isn't already recorded.")
 
       /* Cannot use Fvertical_motion because that function doesn't
         cope with variable-height lines.  */
+      if (b != current_buffer)
+       {
+         old_buffer = current_buffer;
+         set_buffer_internal (b);
+       }
+      
       start_display (&it, w, startp);
       move_it_vertically (&it, window_box_height (w));
-      move_it_past_eol (&it);
+      if (it.current_y < it.last_visible_y)
+       move_it_past_eol (&it);
       value = make_number (IT_CHARPOS (it));
+      
+      if (old_buffer)
+       set_buffer_internal (old_buffer);
     }
   else
     XSETINT (value, BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
@@ -1652,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;
 }
@@ -1669,7 +1677,6 @@ MINIBUF neither nil nor t means never include the minibuffer window.")
   (frame, minibuf, window)
      Lisp_Object frame, minibuf, window;
 {
-
   if (NILP (window))
     window = selected_window;
   if (NILP (frame))
@@ -1764,13 +1771,6 @@ window_loop (type, obj, mini, frames)
   else
     window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
 
-  /* Figure out the last window we're going to mess with.  Since
-     Fnext_window, given the same options, is guaranteed to go in a
-     ring, we can just use Fprevious_window to find the last one.
-
-     We can't just wait until we hit the first window again, because
-     it might be deleted.  */
-
   windows = window_list_1 (window, mini ? Qt : Qnil, frame_arg);
   GCPRO1 (windows);
   best_window = Qnil;
@@ -1799,8 +1799,12 @@ window_loop (type, obj, mini, frames)
                    ? EQ (window, minibuf_window)
                    : 1))
              {
-               UNGCPRO;
-               return window;
+               if (NILP (best_window))
+                 best_window = window;
+               else if (EQ (window, selected_window))
+                 /* For compatibility with 20.x, prefer to return
+                    selected-window.  */
+                 best_window = window;
              }
            break;
 
@@ -1850,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);
@@ -1887,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.  */
@@ -2627,8 +2627,8 @@ set_window_buffer (window, buffer, run_hooks_p)
   XSETFASTINT (w->window_end_vpos, 0);
   bzero (&w->last_cursor, sizeof w->last_cursor);
   w->window_end_valid = Qnil;
-  XSETFASTINT (w->hscroll, 0);
-  XSETFASTINT (w->min_hscroll, 0);
+  w->hscroll = w->min_hscroll = make_number (0);
+  w->vscroll = 0;
   set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
   set_marker_restricted (w->start,
                         make_number (b->last_window_start),
@@ -2729,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))
@@ -3146,15 +3144,13 @@ make_dummy_parent (window)
 {
   Lisp_Object new;
   register struct window *o, *p;
-  register struct Lisp_Vector *vec;
   int i;
 
   o = XWINDOW (window);
-  vec = allocate_vectorlike ((EMACS_INT)VECSIZE (struct window));
+  p = allocate_window ();
   for (i = 0; i < VECSIZE (struct window); ++i)
-    vec->contents[i] = ((struct Lisp_Vector *)o)->contents[i];
-  vec->size = VECSIZE (struct window);
-  p = (struct window *)vec;
+    ((struct Lisp_Vector *) p)->contents[i]
+      = ((struct Lisp_Vector *)o)->contents[i];
   XSETWINDOW (new, p);
 
   XSETFASTINT (p->sequence_number, ++sequence_number);
@@ -3853,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)
@@ -3861,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;
 }
@@ -3906,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,
@@ -3951,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:
@@ -3960,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
@@ -3993,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,
@@ -4140,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,
@@ -4271,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);
 
@@ -4287,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);
@@ -4386,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 ());
@@ -4407,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))
@@ -4493,28 +4492,30 @@ 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);
-
-  if (old_buffer)
-    set_buffer_internal (old_buffer);
-
-  bottom_y = it.current_y + it.max_ascent + it.max_descent;
-
-  if (bottom_y > it.current_y && bottom_y <= it.last_visible_y)
-    /* Hit a line without a terminating newline.  */
-    it.vpos++;
+  bottom_y = line_bottom_y (&it);
 
   /* Add in empty lines at the bottom of the window.  */
   if (bottom_y < height)
     {
-      struct frame *f = XFRAME (w->frame);
-      int rest = height - bottom_y;
-      int lines = rest / CANON_Y_UNIT (f);
-      it.vpos += lines;
+      int uy = CANON_Y_UNIT (it.f);
+      it.vpos += (height - bottom_y + uy - 1) / uy;
     }
 
+  if (old_buffer)
+    set_buffer_internal (old_buffer);
+
   return it.vpos;
 }
 
@@ -4560,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;
@@ -4660,13 +4697,9 @@ zero means top of window, negative means relative to bottom of window.")
        XSETINT (arg, XINT (arg) + lines);
     }
 
-#if 0 /* I don't understand why this is done.  Among other things,
-         it means that C-u 0 M-r moves to line 1, and C-u -1 M-r
-         moves to the line below the window end.  2000-02-05, gerd */
+  /* Skip past a partially visible first line.  */
   if (w->vscroll)
-    /* Skip past a partially visible first line.  */
     XSETINT (arg, XINT (arg) + 1);
-#endif
 
   return Fvertical_motion (arg, window);
 }
@@ -4979,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.  */
@@ -5027,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))
@@ -5249,10 +5282,7 @@ redirection (see `redirect-frame-focus').")
   f = XFRAME (frame);
 
   n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
-  vec = allocate_vectorlike (VECSIZE (struct save_window_data));
-  for (i = 0; i < VECSIZE (struct save_window_data); i++)
-    vec->contents[i] = Qnil;
-  vec->size = VECSIZE (struct save_window_data);
+  vec = allocate_other_vector (VECSIZE (struct save_window_data));
   data = (struct save_window_data *)vec;
 
   XSETFASTINT (data->frame_width, FRAME_WIDTH (f));
@@ -5472,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.  */