Preserve tty top-frames under various window-changing operations.

* 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
This commit is contained in:
Chong Yidong 2012-06-19 14:49:50 +08:00
parent 4e2cc2f31f
commit c6bf302224
8 changed files with 140 additions and 54 deletions

View file

@ -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.
* Installation Changes in Emacs 24.1

View 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.

View 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))))))

View 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)

View 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.

View 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)

View 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;
}
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

View 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 */
/***********************************************************************
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);