]> git.eshelyaron.com Git - emacs.git/commitdiff
Preserve tty top-frames under various window-changing operations.
authorChong Yidong <cyd@gnu.org>
Tue, 19 Jun 2012 06:49:50 +0000 (14:49 +0800)
committerChong Yidong <cyd@gnu.org>
Tue, 19 Jun 2012 06:49:50 +0000 (14:49 +0800)
* subr.el (with-selected-window): Preserve the selected window's
terminal's top-frame.

* window.el (save-selected-window): Likewise.

* frame.c (delete_frame): When selecting a frame on a different
text terminal, do not alter the terminal's top-frame.

* term.c (Ftty_top_frame): New function.

* xdisp.c (format_mode_line_unwind_data): Record the target
frame's selected window and its terminal's top-frame.
(unwind_format_mode_line): Restore them.
(x_consider_frame_title, display_mode_line, Fformat_mode_line):
Callers changed.
(x_consider_frame_title): Do not condition on HAVE_WINDOW_SYSTEM,
since tty frames can be explicitly named.
(prepare_menu_bars): Likewise.

Fixes: debbugs:4702
etc/NEWS
lisp/ChangeLog
lisp/subr.el
lisp/window.el
src/ChangeLog
src/frame.c
src/term.c
src/xdisp.c

index 629743bac4ef7613b300f07d44e5693d2a35fa43..a2f3b95fe416062874cf332fa3a69d1d3b9532ea 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -473,6 +473,8 @@ is detected.
 Emacs now supports mouse highlight, help-echo (in the echo area), and
 mouse-autoselect-window.
 
+** New function `tty-top-frame' returns the topmost frame of a text terminal.
+
 \f
 * Installation Changes in Emacs 24.1
 
index ab66eaf58fb6363dc27c4dfee9929b551fce33f3..71326e107483bf6dca5a9564a385cad3629b4c15 100644 (file)
@@ -1,3 +1,10 @@
+2012-06-19  Chong Yidong  <cyd@gnu.org>
+
+       * subr.el (with-selected-window): Preserve the selected window's
+       terminal's top-frame (Bug#4702).
+
+       * window.el (save-selected-window): Likewise.
+
 2012-06-18  Stefan Monnier  <monnier@iro.umontreal.ca>
 
        * progmodes/python.el (python-rx-constituents): Move backquote.
index 473cc3efddd8c6d2c7b7d7f951372a4a231b5a28..ba9b06d495b24df5a7e87cdb0dc2a5d61493a96a 100644 (file)
@@ -3011,24 +3011,29 @@ the buffer list ordering."
   (declare (indent 1) (debug t))
   ;; Most of this code is a copy of save-selected-window.
   `(let* ((save-selected-window-destination ,window)
+         (save-selected-window-frame
+          (window-frame save-selected-window-destination))
           (save-selected-window-window (selected-window))
-          ;; Selecting a window on another frame changes not only the
-          ;; selected-window but also the frame-selected-window of the
-          ;; destination frame.  So we need to save&restore it.
+          ;; Selecting a window on another frame also changes that
+          ;; frame's frame-selected-window.  We must save&restore it.
           (save-selected-window-other-frame
-           (unless (eq (selected-frame)
-                       (window-frame save-selected-window-destination))
-             (frame-selected-window
-              (window-frame save-selected-window-destination)))))
+           (unless (eq (selected-frame) save-selected-window-frame)
+             (frame-selected-window save-selected-window-frame)))
+         (save-selected-window-top-frame
+           (unless (eq (selected-frame) save-selected-window-frame)
+            (tty-top-frame save-selected-window-frame))))
      (save-current-buffer
        (unwind-protect
            (progn (select-window save-selected-window-destination 'norecord)
                  ,@body)
          ;; First reset frame-selected-window.
-         (if (window-live-p save-selected-window-other-frame)
-             ;; We don't use set-frame-selected-window because it does not
-             ;; pass the `norecord' argument to Fselect_window.
-             (select-window save-selected-window-other-frame 'norecord))
+         (when (window-live-p save-selected-window-other-frame)
+          ;; We don't use set-frame-selected-window because it does not
+          ;; pass the `norecord' argument to Fselect_window.
+          (select-window save-selected-window-other-frame 'norecord)
+          (and (frame-live-p save-selected-window-top-frame)
+               (not (eq (tty-top-frame) save-selected-window-top-frame))
+               (select-frame save-selected-window-top-frame 'norecord)))
          ;; Then reset the actual selected-window.
         (when (window-live-p save-selected-window-window)
           (select-window save-selected-window-window 'norecord))))))
index 6ea882d1ea213de73fc3b442706d65111e4f4830..7c3fe1a082fc9703d677ed65be21280741d6bdee 100644 (file)
@@ -47,12 +47,24 @@ order of recently selected windows and the buffer list ordering
 are not altered by this macro (unless they are altered in BODY)."
   (declare (indent 0) (debug t))
   `(let ((save-selected-window-window (selected-window))
-        ;; It is necessary to save all of these, because calling
-        ;; select-window changes frame-selected-window for whatever
-        ;; frame that window is in.
+        ;; We save and restore all frames' selected windows, because
+        ;; `select-window' can change the frame-selected-window of
+        ;; whatever frame that window is in.  Each text terminal's
+        ;; top-frame is preserved by putting it last in the list.
         (save-selected-window-alist
-         (mapcar (lambda (frame) (cons frame (frame-selected-window frame)))
-                 (frame-list))))
+         (apply 'append
+                (mapcar (lambda (terminal)
+                          (let ((frames (frames-on-display-list terminal))
+                                (top-frame (tty-top-frame terminal))
+                                alist)
+                            (if top-frame
+                                (setq frames
+                                      (cons top-frame
+                                            (delq top-frame frames))))
+                            (dolist (f frames)
+                              (push (cons f (frame-selected-window f))
+                                    alist))))
+                        (terminal-list)))))
      (save-current-buffer
        (unwind-protect
           (progn ,@body)
index df9fcb9dd873ca1ff7ca81cb6716ae64e99c5928..16fcbb0752277bf54d2f4e77b82aae06b2f9b6b1 100644 (file)
@@ -1,3 +1,19 @@
+2012-06-19  Chong Yidong  <cyd@gnu.org>
+
+       * frame.c (delete_frame): When selecting a frame on a different
+       text terminal, do not alter the terminal's top-frame.
+
+       * xdisp.c (format_mode_line_unwind_data): Record the target
+       frame's selected window and its terminal's top-frame.
+       (unwind_format_mode_line): Restore them.
+       (x_consider_frame_title, display_mode_line, Fformat_mode_line):
+       Callers changed.
+       (x_consider_frame_title): Do not condition on HAVE_WINDOW_SYSTEM,
+       since tty frames can be explicitly named.
+       (prepare_menu_bars): Likewise.
+
+       * term.c (Ftty_top_frame): New function.
+
 2012-06-18  Paul Eggert  <eggert@cs.ucla.edu>
 
        Port byte-code-meter to modern targets.
index 39d26ded5a688128ea344fe4dd7e2bc088540215..fc52b07923dfc02a35ccb208963647c8c7186fe8 100644 (file)
@@ -630,8 +630,8 @@ DEFUN ("make-terminal-frame", Fmake_terminal_frame, Smake_terminal_frame,
        doc: /* Create an additional terminal frame, possibly on another terminal.
 This function takes one argument, an alist specifying frame parameters.
 
-You can create multiple frames on a single text-only terminal, but
-only one of them (the selected terminal frame) is actually displayed.
+You can create multiple frames on a single text terminal, but only one
+of them (the selected terminal frame) is actually displayed.
 
 In practice, generally you don't need to specify any parameters,
 except when you want to create a new frame on another terminal.
@@ -865,8 +865,8 @@ something to select a different frame, or until the next time
 this function is called.  If you are using a window system, the
 previously selected frame may be restored as the selected frame
 when returning to the command loop, because it still may have
-the window system's input focus.  On a text-only terminal, the
-next redisplay will display FRAME.
+the window system's input focus.  On a text terminal, the next
+redisplay will display FRAME.
 
 This function returns FRAME, or nil if FRAME has been deleted.  */)
   (Lisp_Object frame, Lisp_Object norecord)
@@ -1254,7 +1254,17 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
          FOR_EACH_FRAME (tail, frame1)
            {
              if (! EQ (frame, frame1) && FRAME_LIVE_P (XFRAME (frame1)))
-               break;
+               {
+                 /* Do not change a text terminal's top-frame.  */
+                 struct frame *f1 = XFRAME (frame1);
+                 if (FRAME_TERMCAP_P (f1) || FRAME_MSDOS_P (f1))
+                   {
+                     Lisp_Object top_frame = FRAME_TTY (f1)->top_frame;
+                     if (!EQ (top_frame, frame))
+                       frame1 = top_frame;
+                   }
+                 break;
+               }
            }
        }
 #ifdef NS_IMPL_COCOA
@@ -1730,8 +1740,8 @@ usually not displayed at all, even in a window system's \"taskbar\".
 Normally you may not make FRAME invisible if all other frames are invisible,
 but if the second optional argument FORCE is non-nil, you may do so.
 
-This function has no effect on text-only terminal frames.  Such frames
-are always considered visible, whether or not they are currently being
+This function has no effect on text terminal frames.  Such frames are
+always considered visible, whether or not they are currently being
 displayed in the terminal.  */)
   (Lisp_Object frame, Lisp_Object force)
 {
@@ -1743,12 +1753,6 @@ displayed in the terminal.  */)
   if (NILP (force) && !other_visible_frames (XFRAME (frame)))
     error ("Attempt to make invisible the sole visible or iconified frame");
 
-#if 0 /* This isn't logically necessary, and it can do GC.  */
-  /* Don't let the frame remain selected.  */
-  if (EQ (frame, selected_frame))
-    do_switch_frame (next_frame (frame, Qt), 0, 0, Qnil)
-#endif
-
   /* Don't allow minibuf_window to remain on a deleted frame.  */
   if (EQ (XFRAME (frame)->minibuffer_window, minibuf_window))
     {
@@ -1816,7 +1820,7 @@ Return nil if FRAME was made invisible, via `make-frame-invisible'.
 On graphical displays, invisible frames are not updated and are
 usually not displayed at all, even in a window system's \"taskbar\".
 
-If FRAME is a text-only terminal frame, this always returns t.
+If FRAME is a text terminal frame, this always returns t.
 Such frames are always considered visible, whether or not they are
 currently being displayed on the terminal.  */)
   (Lisp_Object frame)
@@ -1872,7 +1876,7 @@ doesn't support multiple overlapping frames, this function selects FRAME.  */)
   f = XFRAME (frame);
 
   if (FRAME_TERMCAP_P (f))
-    /* On a text-only terminal select FRAME.  */
+    /* On a text terminal select FRAME.  */
     Fselect_frame (frame, Qnil);
   else
     /* Do like the documentation says. */
@@ -2493,7 +2497,7 @@ not the menu bar).
 In a graphical version with no toolkit, it includes both the tool bar
 and menu bar.
 
-For a text-only terminal, it includes the menu bar.  In this case, the
+For a text terminal, it includes the menu bar.  In this case, the
 result is really in characters rather than pixels (i.e., is identical
 to `frame-height'). */)
   (Lisp_Object frame)
index 3a41552c02e90305b3691dddcf2e7ee2a31b2d2b..5f80718119941c0ca72634afaab77d6af65a49dd 100644 (file)
@@ -2132,7 +2132,7 @@ DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
 
 TERMINAL can be a terminal object, a frame, or nil (meaning the
 selected frame's terminal).  This function always returns nil if
-TERMINAL does not refer to a text-only terminal.  */)
+TERMINAL does not refer to a text terminal.  */)
   (Lisp_Object terminal)
 {
   struct terminal *t = get_tty_terminal (terminal, 0);
@@ -2149,7 +2149,7 @@ DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
 
 TERMINAL can be a terminal object, a frame, or nil (meaning the
 selected frame's terminal).  This function always returns 0 if
-TERMINAL does not refer to a text-only terminal.  */)
+TERMINAL does not refer to a text terminal.  */)
   (Lisp_Object terminal)
 {
   struct terminal *t = get_tty_terminal (terminal, 0);
@@ -2371,7 +2371,7 @@ no effect if used on a non-tty terminal.
 
 TERMINAL can be a terminal object, a frame or nil (meaning the
 selected frame's terminal).  This function always returns nil if
-TERMINAL does not refer to a text-only terminal.  */)
+TERMINAL does not refer to a text terminal.  */)
   (Lisp_Object terminal)
 {
   struct terminal *t = get_terminal (terminal, 1);
@@ -2381,6 +2381,21 @@ TERMINAL does not refer to a text-only terminal.  */)
   return Qnil;
 }
 
+DEFUN ("tty-top-frame", Ftty_top_frame, Stty_top_frame, 0, 1, 0,
+       doc: /* Return the topmost terminal frame on TERMINAL.
+TERMINAL can be a terminal object, a frame or nil (meaning the
+selected frame's terminal).  This function returns nil if TERMINAL
+does not refer to a text terminal.  Otherwise, it returns the
+top-most frame on the text terminal.  */)
+  (Lisp_Object terminal)
+{
+  struct terminal *t = get_terminal (terminal, 1);
+
+  if (t->type == output_termcap)
+    return t->display_info.tty->top_frame;
+  return Qnil;
+}
+
 \f
 
 DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
@@ -3638,6 +3653,7 @@ bigger, or it may make it blink, or it may do nothing at all.  */);
   defsubr (&Stty_no_underline);
   defsubr (&Stty_type);
   defsubr (&Scontrolling_tty_p);
+  defsubr (&Stty_top_frame);
   defsubr (&Ssuspend_tty);
   defsubr (&Sresume_tty);
 #ifdef HAVE_GPM
index f371346589b7d71d88b1c2f8491d55587ecd61c7..dafd22a3fb39aede7a9828da5f7c3a2ae1f585ac 100644 (file)
@@ -8356,9 +8356,9 @@ move_it_in_display_line_to (struct it *it,
                          /* On graphical terminals, newlines may
                             "overflow" into the fringe if
                             overflow-newline-into-fringe is non-nil.
-                            On text-only terminals, newlines may
-                            overflow into the last glyph on the
-                            display line.*/
+                            On text terminals, newlines may overflow
+                            into the last glyph on the display
+                            line.*/
                          if (!FRAME_WINDOW_P (it->f)
                              || IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
                            {
@@ -10821,7 +10821,8 @@ static Lisp_Object mode_line_string_face_prop;
 static Lisp_Object Vmode_line_unwind_vector;
 
 static Lisp_Object
-format_mode_line_unwind_data (struct buffer *obuf,
+format_mode_line_unwind_data (struct frame *target_frame,
+                             struct buffer *obuf,
                              Lisp_Object owin,
                              int save_proptrans)
 {
@@ -10833,7 +10834,7 @@ format_mode_line_unwind_data (struct buffer *obuf,
   Vmode_line_unwind_vector = Qnil;
 
   if (NILP (vector))
-    vector = Fmake_vector (make_number (8), Qnil);
+    vector = Fmake_vector (make_number (10), Qnil);
 
   ASET (vector, 0, make_number (mode_line_target));
   ASET (vector, 1, make_number (MODE_LINE_NOPROP_LEN (0)));
@@ -10848,6 +10849,15 @@ format_mode_line_unwind_data (struct buffer *obuf,
     tmp = Qnil;
   ASET (vector, 6, tmp);
   ASET (vector, 7, owin);
+  if (target_frame)
+    {
+      /* Similarly to `with-selected-window', if the operation selects
+        a window on another frame, we must restore that frame's
+        selected window, and (for a tty) the top-frame.  */
+      ASET (vector, 8, target_frame->selected_window);
+      if (FRAME_TERMCAP_P (target_frame))
+       ASET (vector, 9, FRAME_TTY (target_frame)->top_frame);
+    }
 
   return vector;
 }
@@ -10855,6 +10865,10 @@ format_mode_line_unwind_data (struct buffer *obuf,
 static Lisp_Object
 unwind_format_mode_line (Lisp_Object vector)
 {
+  Lisp_Object old_window = AREF (vector, 7);
+  Lisp_Object target_frame_window = AREF (vector, 8);
+  Lisp_Object old_top_frame = AREF (vector, 9);
+
   mode_line_target = XINT (AREF (vector, 0));
   mode_line_noprop_ptr = mode_line_noprop_buf + XINT (AREF (vector, 1));
   mode_line_string_list = AREF (vector, 2);
@@ -10863,9 +10877,26 @@ unwind_format_mode_line (Lisp_Object vector)
   mode_line_string_face = AREF (vector, 4);
   mode_line_string_face_prop = AREF (vector, 5);
 
-  if (!NILP (AREF (vector, 7)))
-    /* Select window before buffer, since it may change the buffer.  */
-    Fselect_window (AREF (vector, 7), Qt);
+  /* Select window before buffer, since it may change the buffer.  */
+  if (!NILP (old_window))
+    {
+      /* If the operation that we are unwinding had selected a window
+        on a different frame, reset its frame-selected-window.  For a
+        text terminal, reset its top-frame if necessary.  */
+      if (!NILP (target_frame_window))
+       {
+         Lisp_Object frame
+           = WINDOW_FRAME (XWINDOW (target_frame_window));
+
+         if (!EQ (frame, WINDOW_FRAME (XWINDOW (old_window))))
+           Fselect_window (target_frame_window, Qt);
+
+         if (!NILP (old_top_frame) && !EQ (old_top_frame, frame))
+           Fselect_frame (old_top_frame, Qt);
+       }
+
+      Fselect_window (old_window, Qt);
+    }
 
   if (!NILP (AREF (vector, 6)))
     {
@@ -10936,8 +10967,6 @@ store_mode_line_noprop (const char *string, int field_width, int precision)
                             Frame Titles
  ***********************************************************************/
 
-#ifdef HAVE_WINDOW_SYSTEM
-
 /* Set the title of FRAME, if it has changed.  The title format is
    Vicon_title_format if FRAME is iconified, otherwise it is
    frame_title_format.  */
@@ -10981,7 +11010,7 @@ x_consider_frame_title (Lisp_Object frame)
         mode_line_noprop_buf; then display the title.  */
       record_unwind_protect (unwind_format_mode_line,
                             format_mode_line_unwind_data
-                               (current_buffer, selected_window, 0));
+                              (f, current_buffer, selected_window, 0));
 
       Fselect_window (f->selected_window, Qt);
       set_buffer_internal_1 (XBUFFER (XWINDOW (f->selected_window)->buffer));
@@ -11008,10 +11037,6 @@ x_consider_frame_title (Lisp_Object frame)
     }
 }
 
-#endif /* not HAVE_WINDOW_SYSTEM */
-
-
-
 \f
 /***********************************************************************
                              Menu Bars
@@ -11038,7 +11063,6 @@ prepare_menu_bars (void)
   /* Update all frame titles based on their buffer names, etc.  We do
      this before the menu bars so that the buffer-menu will show the
      up-to-date frame titles.  */
-#ifdef HAVE_WINDOW_SYSTEM
   if (windows_or_buffers_changed || update_mode_lines)
     {
       Lisp_Object tail, frame;
@@ -11051,7 +11075,6 @@ prepare_menu_bars (void)
            x_consider_frame_title (frame);
        }
     }
-#endif /* HAVE_WINDOW_SYSTEM */
 
   /* Update the menu bar item lists, if appropriate.  This has to be
      done before any actual redisplay or generation of display lines.  */
@@ -20125,7 +20148,7 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format)
   it.paragraph_embedding = L2R;
 
   record_unwind_protect (unwind_format_mode_line,
-                        format_mode_line_unwind_data (NULL, Qnil, 0));
+                        format_mode_line_unwind_data (NULL, NULL, Qnil, 0));
 
   mode_line_target = MODE_LINE_DISPLAY;
 
@@ -20826,7 +20849,8 @@ are the selected window and the WINDOW's buffer).  */)
      and set that to nil so that we don't alter the outer value.  */
   record_unwind_protect (unwind_format_mode_line,
                         format_mode_line_unwind_data
-                            (old_buffer, selected_window, 1));
+                          (XFRAME (WINDOW_FRAME (XWINDOW (window))),
+                           old_buffer, selected_window, 1));
   mode_line_proptrans_alist = Qnil;
 
   Fselect_window (window, Qt);