(Fredirect_frame_focus): Don't call Ffocus_frame.
[bpt/emacs.git] / src / xdisp.c
index f6ca386..532d548 100644 (file)
@@ -39,6 +39,7 @@ Boston, MA 02111-1307, USA.  */
 
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
 extern void set_frame_menubar ();
+extern int pending_menu_activation;
 #endif
 
 extern int interrupt_input;
@@ -159,6 +160,7 @@ static int debug_end_pos;
 /* Nonzero means display mode line highlighted */
 int mode_line_inverse_video;
 
+static void redisplay_internal ();
 static int message_log_check_duplicate ();
 static void echo_area_display ();
 void mark_window_display_accurate ();
@@ -228,6 +230,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 ()
 {
@@ -323,7 +327,6 @@ message_dolog (m, len, 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.
@@ -361,11 +364,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)
@@ -380,7 +388,7 @@ message2 (m, len)
 }
 
 
-/* The non-logging part of that function.  */
+/* The non-logging counterpart of message2.  */
 
 void
 message2_nolog (m, len)
@@ -410,12 +418,10 @@ message2_nolog (m, len)
       mini_window = FRAME_MINIBUF_WINDOW (selected_frame);
       f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
 
-#ifdef MULTI_FRAME
       FRAME_SAMPLE_VISIBILITY (f);
       if (FRAME_VISIBLE_P (selected_frame)
          && ! FRAME_VISIBLE_P (f))
        Fmake_frame_visible (WINDOW_FRAME (XWINDOW (mini_window)));
-#endif
 
       if (m)
        {
@@ -433,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)
@@ -466,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)
@@ -515,10 +531,10 @@ message (m, a1, a2, a3)
              a[2] = a3;
 
              len = doprnt (FRAME_MESSAGE_BUF (f),
-                           FRAME_WIDTH (f), m, (char *)0, 3, a);
+                           (int) FRAME_WIDTH (f), m, (char *)0, 3, a);
 #else
              len = doprnt (FRAME_MESSAGE_BUF (f),
-                           FRAME_WIDTH (f), m, (char *)0, 3, &a1);
+                           (int) FRAME_WIDTH (f), m, (char *)0, 3, &a1);
 #endif /* NO_ARG_ARRAY */
 
              message2 (FRAME_MESSAGE_BUF (f), len);
@@ -533,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;
@@ -551,7 +567,7 @@ update_echo_area ()
 {
   message2 (echo_area_glyphs, echo_area_glyphs_length);
 }
-
+\f
 static void
 echo_area_display ()
 {
@@ -614,6 +630,8 @@ echo_area_display ()
 
   previous_echo_glyphs = echo_area_glyphs;
 }
+\f
+/* Update frame titles.  */
 
 #ifdef HAVE_WINDOW_SYSTEM
 static char frame_title_buf[512];
@@ -758,6 +776,12 @@ prepare_menu_bars ()
     }
   else
     update_menu_bar (selected_frame, 1);
+
+  /* Motif needs this.  See comment in xmenu.c.
+     Turn it off when pending_menu_activation is not defined.  */
+#ifdef USE_X_TOOLKIT
+  pending_menu_activation = 0;
+#endif
 }
 \f
 /* Do a frame update, taking possible shortcuts into account.
@@ -789,6 +813,19 @@ static FRAME_PTR previous_terminal_frame;
 
 void
 redisplay ()
+{
+  redisplay_internal (0);
+}
+
+/* If PRESERVE_ECHO_AREA is nonzero, it means this redisplay
+   is not in response to any user action; therefore, we should
+   preserve the echo area.  (Actually, our caller does that job.)
+   Perhaps in the future avoid recentering windows
+   if it is not necessary; currently that causes some problems.  */
+
+static void
+redisplay_internal (preserve_echo_area)
+     int preserve_echo_area;
 {
   register struct window *w = XWINDOW (selected_window);
   register int pause;
@@ -800,8 +837,12 @@ redisplay ()
   if (noninteractive)
     return;
 
-#ifdef MULTI_FRAME
-  if (FRAME_TERMCAP_P (selected_frame)
+#ifdef USE_X_TOOLKIT
+  if (popup_activated ())
+    return;
+#endif
+
+  if (! FRAME_WINDOW_P (selected_frame)
       && previous_terminal_frame != selected_frame)
     {
       /* Since frames on an ASCII terminal share the same display area,
@@ -811,7 +852,6 @@ redisplay ()
       XSETFRAME (Vterminal_frame, selected_frame);
     }
   previous_terminal_frame = selected_frame;
-#endif
 
   /* Set the visible flags for all frames.
      Do this before checking for resized or garbaged frames; they want
@@ -844,9 +884,8 @@ redisplay ()
   if (windows_or_buffers_changed)
     update_mode_lines++;
 
-  /* Detect case that we need to write a star in the mode line.  */
-  if (XFASTINT (w->last_modified) < MODIFF
-      && XFASTINT (w->last_modified) <= SAVE_MODIFF)
+  /* Detect case that we need to write or remove a star in the mode line.  */
+  if ((SAVE_MODIFF < MODIFF) != !NILP (w->last_had_star))
     {
       w->update_mode_line = Qt;
       if (buffer_shared > 1)
@@ -984,6 +1023,7 @@ redisplay ()
         then we can't just move the cursor.  */
       else if (! (!NILP (Vtransient_mark_mode)
                  && !NILP (current_buffer->mark_active))
+              && w == XWINDOW (current_buffer->last_selected_window)
               && NILP (w->region_showing)
               && !cursor_in_echo_area)
        {
@@ -1036,7 +1076,7 @@ redisplay ()
       FOR_EACH_FRAME (tail, frame)
        {
          FRAME_PTR f = XFRAME (frame);
-         if (! FRAME_TERMCAP_P (f) || f == selected_frame)
+         if (FRAME_WINDOW_P (f) || f == selected_frame)
            {
 
              /* Mark all the scroll bars to be removed; we'll redeem the ones
@@ -1045,7 +1085,7 @@ redisplay ()
                (*condemn_scroll_bars_hook) (f);
 
              if (FRAME_VISIBLE_P (f))
-               redisplay_windows (FRAME_ROOT_WINDOW (f));
+               redisplay_windows (FRAME_ROOT_WINDOW (f), preserve_echo_area);
 
              /* Any scroll bars which redisplay_windows should have nuked
                 should now go away.  */
@@ -1056,7 +1096,7 @@ redisplay ()
     }
   else if (FRAME_VISIBLE_P (selected_frame))
     {
-      redisplay_window (selected_window, 1);
+      redisplay_window (selected_window, 1, preserve_echo_area);
       if (XFASTINT (w->width) != FRAME_WIDTH (selected_frame))
        preserve_other_columns (w);
     }
@@ -1069,7 +1109,6 @@ update:
     unrequest_sigio ();
   stop_polling ();
 
-#ifdef MULTI_FRAME
   if (all_windows)
     {
       Lisp_Object tail;
@@ -1085,7 +1124,7 @@ update:
 
          f = XFRAME (XCONS (tail)->car);
 
-         if ((! FRAME_TERMCAP_P (f) || f == selected_frame)
+         if ((FRAME_WINDOW_P (f) || f == selected_frame)
              && FRAME_VISIBLE_P (f))
            {
              pause |= update_frame (f, 0, 0);
@@ -1099,7 +1138,6 @@ update:
        }
     }
   else
-#endif /* MULTI_FRAME */
     {
       if (FRAME_VISIBLE_P (selected_frame))
        pause = update_frame (selected_frame, 0, 0);
@@ -1118,8 +1156,7 @@ update:
        mini_window = FRAME_MINIBUF_WINDOW (selected_frame);
        mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
        
-       if (mini_frame != selected_frame
-           && ! FRAME_TERMCAP_P (mini_frame))
+       if (mini_frame != selected_frame && FRAME_WINDOW_P (mini_frame))
          pause |= update_frame (mini_frame, 0, 0);
       }
     }
@@ -1165,6 +1202,9 @@ update:
          b->clip_changed = 0;
          w->update_mode_line = Qnil;
          XSETFASTINT (w->last_modified, BUF_MODIFF (b));
+         w->last_had_star
+           = (BUF_MODIFF (XBUFFER (w->buffer)) > BUF_SAVE_MODIFF (XBUFFER (w->buffer))
+              ? Qt : Qnil);
          w->window_end_valid = w->buffer;
          last_arrow_position = Voverlay_arrow_position;
          last_arrow_string = Voverlay_arrow_string;
@@ -1210,11 +1250,11 @@ redisplay_preserve_echo_area ()
   if (echo_area_glyphs == 0 && previous_echo_glyphs != 0)
     {
       echo_area_glyphs = previous_echo_glyphs;
-      redisplay ();
+      redisplay_internal (1);
       echo_area_glyphs = 0;
     }
   else
-    redisplay ();
+    redisplay_internal (1);
 }
 
 void
@@ -1233,10 +1273,14 @@ mark_window_display_accurate (window, flag)
        {
          XSETFASTINT (w->last_modified,
                       !flag ? 0 : BUF_MODIFF (XBUFFER (w->buffer)));
+         w->last_had_star
+           = (BUF_MODIFF (XBUFFER (w->buffer)) > BUF_SAVE_MODIFF (XBUFFER (w->buffer))
+              ? Qt : Qnil);
 
          /* Record if we are showing a region, so can make sure to
             update it fully at next redisplay.  */
          w->region_showing = (!NILP (Vtransient_mark_mode)
+                              && w == XWINDOW (current_buffer->last_selected_window)
                               && !NILP (XBUFFER (w->buffer)->mark_active)
                               ? Fmarker_position (XBUFFER (w->buffer)->mark)
                               : Qnil);
@@ -1244,7 +1288,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))
@@ -1287,7 +1331,7 @@ update_menu_bar (f, save_match_data)
   if (update_mode_lines)
     w->update_mode_line = Qt;
 
-  if (FRAME_X_P (f)
+  if (FRAME_WINDOW_P (f)
       ?
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
       FRAME_EXTERNAL_MENU_BAR (f) 
@@ -1305,9 +1349,9 @@ update_menu_bar (f, save_match_data)
         windows_or_buffers_changed anyway.  */
       if (windows_or_buffers_changed
          || !NILP (w->update_mode_line)
-         || (XFASTINT (w->last_modified) < MODIFF
-             && (XFASTINT (w->last_modified)
-                 <= BUF_SAVE_MODIFF (XBUFFER (w->buffer))))
+         || ((BUF_SAVE_MODIFF (XBUFFER (w->buffer))
+              < BUF_MODIFF (XBUFFER (w->buffer)))
+             != !NILP (w->last_had_star))
          || ((!NILP (Vtransient_mark_mode)
               && !NILP (XBUFFER (w->buffer)->mark_active))
              != !NILP (w->region_showing)))
@@ -1330,12 +1374,21 @@ 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));
+         /* Redisplay the menu bar in case we changed it.  */
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
-         if (FRAME_X_P (f))
+         if (FRAME_WINDOW_P (f))
            set_frame_menubar (f, 0, 0);
-#endif /* USE_X_TOOLKIT || HAVE_NTGUI */
+         else
+           /* On a terminal screen, the menu bar is an ordinary screen
+            line, and this makes it get updated.  */
+           w->update_mode_line = Qt;
+#else /* ! (USE_X_TOOLKIT || HAVE_NTGUI) */
+         /* In the non-toolkit version, the menu bar is an ordinary screen
+            line, and this makes it get updated.  */
+         w->update_mode_line = Qt;
+#endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI) */
 
          unbind_to (count, Qnil);
          set_buffer_internal_1 (prev);
@@ -1348,19 +1401,20 @@ int do_id = 1;
 /* Redisplay WINDOW and its subwindows and siblings.  */
 
 static void
-redisplay_windows (window)
+redisplay_windows (window, preserve_echo_area)
      Lisp_Object window;
+     int preserve_echo_area;
 {
   for (; !NILP (window); window = XWINDOW (window)->next)
-    redisplay_window (window, 0);
+    redisplay_window (window, 0, preserve_echo_area);
 }
 
 /* Redisplay window WINDOW and its subwindows.  */
 
 static void
-redisplay_window (window, just_this_one)
+redisplay_window (window, just_this_one, preserve_echo_area)
      Lisp_Object window;
-     int just_this_one;
+     int just_this_one, preserve_echo_area;
 {
   register struct window *w = XWINDOW (window);
   FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
@@ -1382,12 +1436,12 @@ redisplay_window (window, just_this_one)
 
   if (!NILP (w->vchild))
     {
-      redisplay_windows (w->vchild);
+      redisplay_windows (w->vchild, preserve_echo_area);
       return;
     }
   if (!NILP (w->hchild))
     {
-      redisplay_windows (w->hchild);
+      redisplay_windows (w->hchild, preserve_echo_area);
       return;
     }
   if (NILP (w->buffer))
@@ -1523,8 +1577,11 @@ 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);
+           }
        }
       XSETFASTINT (w->last_modified, 0);
       if (startp < BEGV) startp = BEGV;
@@ -1653,8 +1710,16 @@ redisplay_window (window, just_this_one)
        goto done;
     }
   else if (startp >= BEGV && startp <= ZV
-          /* Avoid starting display at end of buffer! */
-          && (startp < ZV || startp == BEGV
+          && (startp < ZV
+              /* Avoid starting at end of buffer.  */
+#if 0 /* This change causes trouble for M-! finger & RET.
+        It will have to be considered later.  */
+              || ! EQ (window, selected_window)
+              /* Don't do the recentering if redisplay
+                 is not for no user action.  */
+              || preserve_echo_area
+#endif
+              || startp == BEGV
               || (XFASTINT (w->last_modified) >= MODIFF)))
     {
       /* Try to redisplay starting at same place as before */
@@ -1699,8 +1764,12 @@ 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));
+           {
+             Fset_marker (w->start, make_number (pos.bufpos), Qnil);
+             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)
            {
@@ -1727,8 +1796,11 @@ recenter:
      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);
@@ -1754,7 +1826,7 @@ done:
 
   /* When we reach a frame's selected window, redo the frame's menu bar.  */
   if (update_mode_line
-      && (FRAME_X_P (f)
+      && (FRAME_WINDOW_P (f)
          ?
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
          FRAME_EXTERNAL_MENU_BAR (f) 
@@ -2487,7 +2559,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
   /* 1 if we should highlight the region.  */
   int highlight_region
-    = !NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active);
+    = (!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active)
+       && XWINDOW (current_buffer->last_selected_window) == w);
   int region_beg, region_end;
 
   int selective = (INTEGERP (current_buffer->selective_display)
@@ -2756,7 +2829,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
          /* 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)))
+         if (pos >= next_face_change
+             && (FRAME_WINDOW_P (f) || FRAME_MSDOS_P (f)))
            current_face = compute_char_face (f, w, pos,
                                              region_beg, region_end,
                                              &next_face_change, pos + 50, 0);
@@ -3193,7 +3267,8 @@ display_menu_bar (w)
   int i;
 
 #ifdef HAVE_NTGUI
-  return;
+  if (!NILP (Vwindow_system))
+    return;
 #endif
 
 #ifdef USE_X_TOOLKIT
@@ -3204,14 +3279,14 @@ display_menu_bar (w)
   get_display_line (f, vpos, 0);
 
   items = FRAME_MENU_BAR_ITEMS (f);
-  for (i = 0; i < XVECTOR (items)->size; i += 3)
+  for (i = 0; i < XVECTOR (items)->size; i += 4)
     {
       Lisp_Object pos, string;
       string = XVECTOR (items)->contents[i + 1];
       if (NILP (string))
        break;
 
-      XSETFASTINT (XVECTOR (items)->contents[i + 2], hpos);
+      XSETFASTINT (XVECTOR (items)->contents[i + 3], hpos);
 
       if (hpos < maxendcol)
        hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
@@ -3664,13 +3739,11 @@ 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
+      if (!NILP (f->title))
+       return (char *) XSTRING (f->title)->data;
+      if (f->explicit_name || ! FRAME_WINDOW_P (f))
+       return (char *) XSTRING (f->name)->data;
       return "Emacs";
-#endif
 
     case 'f': 
       obj = b->filename;