]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
(redisplay_window): If window-scroll-functions change
[gnu-emacs] / src / xdisp.c
index f3876c9d0204a7f40470f72a82d2ab87c198084d..7fc3425dc0d6dca41bd9c587b52bc99b01ec9bc0 100644 (file)
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include <config.h>
@@ -36,7 +37,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "intervals.h"
 #include "keyboard.h"
 
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
 extern void set_frame_menubar ();
 #endif
 
@@ -50,7 +51,7 @@ extern Lisp_Object Voverriding_local_map_menu_flag;
 
 Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
 Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
-Lisp_Object Qredisplay_end_trigger_hook;
+Lisp_Object Qredisplay_end_trigger_functions;
 
 /* Nonzero means print newline to stdout before next minibuffer message.  */
 
@@ -227,6 +228,8 @@ static int line_number_display_limit;
    t means infinite.  nil means don't log at all.  */
 Lisp_Object Vmessage_log_max;
 \f
+/* Output a newline in the *Messages* buffer if "needs" one.  */
+
 void
 message_log_maybe_newline ()
 {
@@ -248,6 +251,7 @@ message_dolog (m, len, nlflag)
     {
       struct buffer *oldbuf;
       int oldpoint, oldbegv, oldzv;
+      int old_windows_or_buffers_changed = windows_or_buffers_changed;
 
       oldbuf = current_buffer;
       Fset_buffer (Fget_buffer_create (build_string ("*Messages*")));
@@ -316,11 +320,11 @@ message_dolog (m, len, nlflag)
       ZV = oldzv;
       TEMP_SET_PT (oldpoint);
       set_buffer_internal (oldbuf);
+      windows_or_buffers_changed = old_windows_or_buffers_changed;
       message_log_need_newline = !nlflag;
     }
 }
 
-
 /* We are at the end of the buffer after just having inserted a newline.
    (Note: We depend on the fact we won't be crossing the gap.)
    Check to see if the most recent message looks a lot like the previous one.
@@ -358,11 +362,16 @@ message_log_check_duplicate (prev_bol, this_bol)
     }
   return 0;
 }
-
+\f
 /* Display an echo area message M with a specified length of LEN chars.
-   The string may include null characters.  If m is 0, clear out any
+   The string may include null characters.  If M is 0, clear out any
    existing message, and let the minibuffer text show through.
-   Do not pass text that is stored in a Lisp string.  */
+
+   The buffer M must continue to exist until after the echo area
+   gets cleared or some other message gets displayed there.
+
+   Do not pass text that is stored in a Lisp string.
+   Do not pass text in a buffer that was alloca'd.  */
 
 void
 message2 (m, len)
@@ -377,7 +386,7 @@ message2 (m, len)
 }
 
 
-/* The non-logging part of that function.  */
+/* The non-logging counterpart of message2.  */
 
 void
 message2_nolog (m, len)
@@ -430,6 +439,15 @@ message2_nolog (m, len)
        (*frame_up_to_date_hook) (f);
     }
 }
+\f
+/* Display a null-terminated echo area message M.  If M is 0, clear out any
+   existing message, and let the minibuffer text show through.
+
+   The buffer M must continue to exist until after the echo area
+   gets cleared or some other message gets displayed there.
+
+   Do not pass text that is stored in a Lisp string.
+   Do not pass text in a buffer that was alloca'd.  */
 
 void
 message1 (m)
@@ -463,8 +481,9 @@ truncate_echo_area (len)
    zero if being used by message.  */
 int message_buf_print;
 
-/* Dump an informative message to the minibuf.  If m is 0, clear out
+/* Dump an informative message to the minibuf.  If M is 0, clear out
    any existing message, and let the minibuffer text show through.  */
+
 /* VARARGS 1 */
 void
 message (m, a1, a2, a3)
@@ -530,7 +549,7 @@ message (m, a1, a2, a3)
     }
 }
 
-/* The non-logging version of that function.  */
+/* The non-logging version of message.  */
 void
 message_nolog (m, a1, a2, a3)
      char *m;
@@ -548,7 +567,7 @@ update_echo_area ()
 {
   message2 (echo_area_glyphs, echo_area_glyphs_length);
 }
-
+\f
 static void
 echo_area_display ()
 {
@@ -611,8 +630,10 @@ echo_area_display ()
 
   previous_echo_glyphs = echo_area_glyphs;
 }
+\f
+/* Update frame titles.  */
 
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_WINDOW_SYSTEM
 static char frame_title_buf[512];
 static char *frame_title_ptr;
 
@@ -641,7 +662,7 @@ x_consider_frame_title (frame)
   int len;
   FRAME_PTR f = XFRAME (frame);
 
-  if (!FRAME_X_P (f) || FRAME_MINIBUF_ONLY_P (f) || f->explicit_name)
+  if (!(FRAME_WINDOW_P (f) || FRAME_MINIBUF_ONLY_P (f) || f->explicit_name))
     return;
 
   /* Do we have more than one visible frame on this X display?  */
@@ -706,8 +727,8 @@ prepare_menu_bars ()
      create its menu bar using the name `emacs' if no other name
      has yet been specified."
      I think that is no longer a concern.  */
-#ifdef HAVE_X_WINDOWS
-  if (windows_or_buffers_changed)
+#ifdef HAVE_WINDOW_SYSTEM
+  if (windows_or_buffers_changed || update_mode_lines)
     {
       Lisp_Object tail, frame;
 
@@ -797,6 +818,11 @@ redisplay ()
   if (noninteractive)
     return;
 
+#ifdef USE_X_TOOLKIT
+  if (popup_activated ())
+    return;
+#endif
+
 #ifdef MULTI_FRAME
   if (FRAME_TERMCAP_P (selected_frame)
       && previous_terminal_frame != selected_frame)
@@ -1241,7 +1267,7 @@ mark_window_display_accurate (window, flag)
 
       w->window_end_valid = w->buffer;
       w->update_mode_line = Qnil;
-      if (!NILP (w->buffer))
+      if (!NILP (w->buffer) && flag)
        XBUFFER (w->buffer)->clip_changed = 0;
 
       if (!NILP (w->vchild))
@@ -1284,13 +1310,14 @@ update_menu_bar (f, save_match_data)
   if (update_mode_lines)
     w->update_mode_line = Qt;
 
-  if (
-#ifdef USE_X_TOOLKIT
+  if (FRAME_WINDOW_P (f)
+      ?
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
       FRAME_EXTERNAL_MENU_BAR (f) 
 #else
       FRAME_MENU_BAR_LINES (f) > 0
 #endif
-      )
+      : FRAME_MENU_BAR_LINES (f) > 0)
     {
       /* If the user has switched buffers or windows, we need to
         recompute to reflect the new bindings.  But we'll
@@ -1326,11 +1353,12 @@ update_menu_bar (f, save_match_data)
             really recompute the menubar from the value.  */
          if (! NILP (Vlucid_menu_bar_dirty_flag))
            call0 (Qrecompute_lucid_menubar);
-         call1 (Vrun_hooks, Qmenu_bar_update_hook);
+         safe_run_hooks (Qmenu_bar_update_hook);
          FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
-#ifdef USE_X_TOOLKIT
-         set_frame_menubar (f, 0, 0);
-#endif /* USE_X_TOOLKIT */
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
+         if (FRAME_WINDOW_P (f))
+           set_frame_menubar (f, 0, 0);
+#endif /* USE_X_TOOLKIT || HAVE_NTGUI */
 
          unbind_to (count, Qnil);
          set_buffer_internal_1 (prev);
@@ -1498,11 +1526,16 @@ redisplay_window (window, just_this_one)
      unless the specified location is outside the accessible range.  */
   if (!NILP (w->force_start))
     {
+      w->force_start = Qnil;
       /* Forget any recorded base line for line number display.  */
       w->base_line_number = Qnil;
       /* Redisplay the mode line.  Select the buffer properly for that.
         Also, run the hook window-scroll-functions
         because we have scrolled.  */
+      /* Note, we do this after clearing force_start because
+        if there's an error, it is better to forget about force_start
+        than to get into an infinite loop calling the hook functions
+        and having them get more errors.  */
       if (!update_mode_line
          || ! NILP (Vwindow_scroll_functions))
        {
@@ -1513,10 +1546,12 @@ redisplay_window (window, just_this_one)
          update_mode_line = 1;
          w->update_mode_line = Qt;
          if (! NILP (Vwindow_scroll_functions))
-           run_hook_with_args_2 (Qwindow_scroll_functions, window,
-                                 make_number (startp));
+           {
+             run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                                   make_number (startp));
+             startp = marker_position (w->start);
+           }
        }
-      w->force_start = Qnil;
       XSETFASTINT (w->last_modified, 0);
       if (startp < BEGV) startp = BEGV;
       if (startp > ZV)   startp = ZV;
@@ -1557,7 +1592,7 @@ redisplay_window (window, just_this_one)
     }
 
   /* Handle case where text has not changed, only point,
-     and it has not moved off the frame */
+     and it has not moved off the frame */
 
   /* This code is not used for minibuffer for the sake of
      the case of redisplaying to replace an echo area message;
@@ -1675,7 +1710,8 @@ redisplay_window (window, just_this_one)
 
   /* Try to scroll by specified few lines */
 
-  if (scroll_step && !current_buffer->clip_changed)
+  if (scroll_step && !current_buffer->clip_changed
+      && startp >= BEGV && startp <= ZV)
     {
       if (PT > startp)
        {
@@ -1689,8 +1725,11 @@ redisplay_window (window, just_this_one)
       if (PT >= pos.bufpos)
        {
          if (! NILP (Vwindow_scroll_functions))
-           run_hook_with_args_2 (Qwindow_scroll_functions, window,
-                                 make_number (pos.bufpos));
+           {
+             run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                                   make_number (pos.bufpos));
+             pos.bufpos = marker_position (w->start);
+           }
          try_window (window, pos.bufpos);
          if (cursor_vpos >= 0)
            {
@@ -1713,9 +1752,15 @@ recenter:
   w->base_line_number = Qnil;
 
   pos = *vmotion (PT, - (height / 2), w);
+  /* Set startp here explicitly in case that helps avoid an infinite loop
+     in case the window-scroll-functions functions get errors.  */
+  Fset_marker (w->start, make_number (pos.bufpos), Qnil);
   if (! NILP (Vwindow_scroll_functions))
-    run_hook_with_args_2 (Qwindow_scroll_functions, window,
-                         make_number (pos.bufpos));
+    {
+      run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                           make_number (pos.bufpos));
+      pos.bufpos = marker_position (w->start);
+    }
   try_window (window, pos.bufpos);
 
   startp = marker_position (w->start);
@@ -1741,11 +1786,14 @@ done:
 
   /* When we reach a frame's selected window, redo the frame's menu bar.  */
   if (update_mode_line
-#ifdef USE_X_TOOLKIT
-      && FRAME_EXTERNAL_MENU_BAR (f) 
+      && (FRAME_WINDOW_P (f)
+         ?
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
+         FRAME_EXTERNAL_MENU_BAR (f) 
 #else
-      && FRAME_MENU_BAR_LINES (f) > 0
+         FRAME_MENU_BAR_LINES (f) > 0
 #endif
+         : FRAME_MENU_BAR_LINES (f) > 0)
       && EQ (FRAME_SELECTED_WINDOW (f), window))
     display_menu_bar (w);
 
@@ -1894,7 +1942,7 @@ try_window_id (window)
   struct position val, bp, ep, xp, pp;
   int scroll_amount = 0;
   int delta;
-  int tab_offset, epto;
+  int tab_offset, epto, old_tick;
 
   if (GPT - BEG < beg_unchanged)
     beg_unchanged = GPT - BEG;
@@ -2088,8 +2136,8 @@ try_window_id (window)
                 lines' charstarts in the case where the text of the
                 screen line at bp.vpos has changed.
                 (This can happen in a deletion that ends in mid-line.)
-                To adjust properly, we need to make things constent at
-                the position ep.
+                To adjust properly, we need to make things consistent
+                at the position ep.
                 So do a second adjust to make that happen.
                 Note that stop_vpos >= ep.vpos, so it is sufficient
                 to update the charstarts for lines at ep.vpos and below.  */
@@ -2139,9 +2187,15 @@ try_window_id (window)
      to account for passing the line that that character really starts in.  */
   if (val.hpos < lmargin)
     tab_offset += width;
+  old_tick = MODIFF;
   while (vpos < stop_vpos)
     {
       val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
+      /* If display_text_line ran a hook and changed some text,
+        redisplay all the way to bottom of buffer
+        So that we show the changes.  */
+      if (old_tick != MODIFF)
+       stop_vpos = height;
       tab_offset += width;
       if (val.vpos) tab_offset = 0;
       if (pos != val.bufpos)
@@ -2700,22 +2754,13 @@ display_text_line (w, start, vpos, hpos, taboffset)
              break;
            }
 
-#ifdef HAVE_FACES
-         /* Did we hit a face change?  Figure out what face we should
-            use now.  We also hit this the first time through the
-            loop, to see what face we should start with.  */
-         if (pos >= next_face_change && FRAME_X_P (f))
-           current_face = compute_char_face (f, w, pos,
-                                             region_beg, region_end,
-                                             &next_face_change, pos + 50, 0);
-#endif
-
          /* Figure out where (if at all) the
             redisplay_end_trigger-hook should run.  */
-         if (MARKERP (current_buffer->redisplay_end_trigger))
-           e_t_h = marker_position (current_buffer->redisplay_end_trigger);
-         else if (INTEGERP (current_buffer->redisplay_end_trigger))
-           e_t_h = XINT (current_buffer->redisplay_end_trigger);
+         if (MARKERP (w->redisplay_end_trigger)
+             && XMARKER (w->redisplay_end_trigger)->buffer != 0)
+           e_t_h = marker_position (w->redisplay_end_trigger);
+         else if (INTEGERP (w->redisplay_end_trigger))
+           e_t_h = XINT (w->redisplay_end_trigger);
          else
            e_t_h = ZV;
 
@@ -2723,11 +2768,32 @@ display_text_line (w, start, vpos, hpos, taboffset)
             run the hook.  */
          if (pos >= e_t_h && e_t_h != ZV)
            {
-             call1 (Vrun_hooks, Qredisplay_end_trigger_hook);
-             current_buffer->redisplay_end_trigger = Qnil;
+             Lisp_Object args[3];
+
+             args[0] = Qredisplay_end_trigger_functions;
+             XSETWINDOW (args[1], w);
+             XSETINT (args[2], e_t_h);
+
+             /* Since we are *trying* to run these functions,
+                don't try to run them again, even if they get an error.  */
+             w->redisplay_end_trigger = Qnil;
+             Frun_hook_with_args (3, args);
+
              e_t_h = ZV;
+             /* Notice if it changed the face of this character.  */
+             next_face_change = pos;
            }
 
+#ifdef HAVE_FACES
+         /* Did we hit a face change?  Figure out what face we should
+            use now.  We also hit this the first time through the
+            loop, to see what face we should start with.  */
+         if (pos >= next_face_change && (FRAME_WINDOW_P (f)))
+           current_face = compute_char_face (f, w, pos,
+                                             region_beg, region_end,
+                                             &next_face_change, pos + 50, 0);
+#endif
+
          /* Compute the next place we need to stop
             and do something special; set PAUSE.  */
 
@@ -3158,25 +3224,17 @@ display_menu_bar (w)
   int hpos = 0;
   int i;
 
-#ifndef USE_X_TOOLKIT
-  if (FRAME_MENU_BAR_LINES (f) <= 0)
+#ifdef HAVE_NTGUI
+  return;
+#endif
+
+#ifdef USE_X_TOOLKIT
+  if (FRAME_X_P (f))
     return;
+#endif /* USE_X_TOOLKIT */
 
   get_display_line (f, vpos, 0);
 
-#if 0
-  /* Show in the menu bar how to invoke it.  */
-  if (!FRAME_X_P (f))
-    {
-      hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
-                            "M-`", 3,
-                            hpos, 0, 0, hpos, maxendcol);
-      /* Put 2 spaces after it.  */
-      hpos = display_string (w, vpos, "", 0, hpos, 0, 0,
-                            hpos + 2, maxendcol);
-    }
-#endif
-
   items = FRAME_MENU_BAR_ITEMS (f);
   for (i = 0; i < XVECTOR (items)->size; i += 3)
     {
@@ -3212,7 +3270,6 @@ display_menu_bar (w)
   vpos++;
   while (vpos < FRAME_MENU_BAR_LINES (f))
     get_display_line (f, vpos++, 0);
-#endif /* not USE_X_TOOLKIT */
 }
 \f
 /* Display the mode line for window w */
@@ -3640,6 +3697,8 @@ decode_mode_spec (w, c, spec_width, maxwidth)
     case 'F':
       /* %F displays the frame name.  */
 #ifdef MULTI_FRAME
+      if (!NILP (selected_frame->title))
+       return (char *) XSTRING (selected_frame->title)->data;
       return (char *) XSTRING (selected_frame->name)->data;
 #else
       return "Emacs";
@@ -3779,7 +3838,11 @@ decode_mode_spec (w, c, spec_width, maxwidth)
          return "Top";
        else
          {
-           total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total;
+           if (total > 1000000)
+             /* Do it differently for a large value, to avoid overflow.  */
+             total = ((pos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100);
+           else
+             total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total;
            /* We can't normally display a 3-digit number,
               so get us a 2-digit number that is close.  */
            if (total == 100)
@@ -3805,7 +3868,11 @@ decode_mode_spec (w, c, spec_width, maxwidth)
          }
        else
          {
-           total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total;
+           if (total > 1000000)
+             /* Do it differently for a large value, to avoid overflow.  */
+             total = ((botpos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100);
+           else
+             total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total;
            /* We can't normally display a 3-digit number,
               so get us a 2-digit number that is close.  */
            if (total == 100)
@@ -4007,6 +4074,7 @@ display_string (w, vpos, string, length, hpos, truncate,
      int mincol, maxcol;
 {
   register int c;
+  int truncated;
   register GLYPH *p1;
   int hscroll = XINT (w->hscroll);
   int tab_width = XINT (XBUFFER (w->buffer)->tab_width);
@@ -4059,7 +4127,10 @@ display_string (w, vpos, string, length, hpos, truncate,
   if (maxcol >= 0 && mincol > maxcol)
     mincol = maxcol;
 
-  while (p1 < end)
+  /* We set truncated to 1 if we get stopped by trying to pass END
+     (that is, trying to pass MAXCOL.)  */
+  truncated = 0;
+  while (1)
     {
       if (length == 0)
        break;
@@ -4071,6 +4142,12 @@ display_string (w, vpos, string, length, hpos, truncate,
       else if (c == 0)
        break;
 
+      if (p1 >= end)
+       {
+         truncated = 1;
+         break;
+       }
+
       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
        {
          p1 = copy_part_of_rope (f, p1, start,
@@ -4124,7 +4201,7 @@ display_string (w, vpos, string, length, hpos, truncate,
        }
     }
 
-  if (c && length > 0)
+  if (truncated)
     {
       p1 = end;
       if (truncate) *p1++ = fix_glyph (f, truncate, 0);
@@ -4242,8 +4319,8 @@ syms_of_xdisp ()
   staticpro (&Qwindow_scroll_functions);
   Qwindow_scroll_functions = intern ("window-scroll-functions");
 
-  staticpro (&Qredisplay_end_trigger_hook);
-  Qredisplay_end_trigger_hook = intern ("redisplay-end-trigger-hook");
+  staticpro (&Qredisplay_end_trigger_functions);
+  Qredisplay_end_trigger_functions = intern ("redisplay-end-trigger-functions");
 
   staticpro (&last_arrow_position);
   staticpro (&last_arrow_string);