From c6bf30222430f41fbb696e296f0f63f465eefc35 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Tue, 19 Jun 2012 14:49:50 +0800 Subject: [PATCH] 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 --- etc/NEWS | 2 ++ lisp/ChangeLog | 7 ++++++ lisp/subr.el | 27 +++++++++++++--------- lisp/window.el | 22 ++++++++++++++---- src/ChangeLog | 16 +++++++++++++ src/frame.c | 36 ++++++++++++++++------------- src/term.c | 22 +++++++++++++++--- src/xdisp.c | 62 ++++++++++++++++++++++++++++++++++---------------- 8 files changed, 140 insertions(+), 54 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 629743bac4e..a2f3b95fe41 100644 --- 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. + * Installation Changes in Emacs 24.1 diff --git a/lisp/ChangeLog b/lisp/ChangeLog index ab66eaf58fb..71326e10748 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,10 @@ +2012-06-19 Chong Yidong + + * 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 * progmodes/python.el (python-rx-constituents): Move backquote. diff --git a/lisp/subr.el b/lisp/subr.el index 473cc3efddd..ba9b06d495b 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -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)))))) diff --git a/lisp/window.el b/lisp/window.el index 6ea882d1ea2..7c3fe1a082f 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -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) diff --git a/src/ChangeLog b/src/ChangeLog index df9fcb9dd87..16fcbb07522 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,19 @@ +2012-06-19 Chong Yidong + + * 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 Port byte-code-meter to modern targets. diff --git a/src/frame.c b/src/frame.c index 39d26ded5a6..fc52b07923d 100644 --- a/src/frame.c +++ b/src/frame.c @@ -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) diff --git a/src/term.c b/src/term.c index 3a41552c02e..5f807181199 100644 --- a/src/term.c +++ b/src/term.c @@ -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 diff --git a/src/xdisp.c b/src/xdisp.c index f371346589b..dafd22a3fb3 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -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); -- 2.39.2