commit 15315780ae36cc2af6e276165562dc793334c2f9 (HEAD, refs/remotes/origin/master) Author: Gerd Möllmann Date: Thu Jan 23 20:53:50 2025 +0100 Handle update of invisible tty frames (bug#75056) * src/dispnew.c (combine_updates_for_frame): Don't assume root frame is visible. diff --git a/src/dispnew.c b/src/dispnew.c index 9726bf70660..e4567f6970c 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3964,11 +3964,20 @@ combine_updates_for_frame (struct frame *f, bool inhibit_scrolling) { #ifndef HAVE_ANDROID struct frame *root = root_frame (f); - eassert (FRAME_VISIBLE_P (root)); + + /* Determine visible frames on the root frame, including the root + frame itself. Note that there are cases, see bug#75056, where we + can be called for invisible frames. */ + Lisp_Object z_order = frames_in_reverse_z_order (root, true); + if (NILP (z_order)) + { + Lisp_Object root_frame; + XSETFRAME (root_frame, root); + z_order = Fcons (root_frame, Qnil); + } /* Process child frames in reverse z-order, topmost last. For each child, copy what we need to the root's desired matrix. */ - Lisp_Object z_order = frames_in_reverse_z_order (root, true); struct frame *topmost_child = NULL; for (Lisp_Object tail = XCDR (z_order); CONSP (tail); tail = XCDR (tail)) { commit f14c24dbe7f65786115f8f62a337be45996c38b8 Author: Stefan Kangas Date: Fri Jan 24 00:44:21 2025 +0100 Support loading dynamic docstrings from Emacs <29 * src/doc.c (get_doc_string): Take absolute value to be compatible with bytecode from Emacs <29. diff --git a/src/doc.c b/src/doc.c index 0ce1274fe12..6f4ce79f1f1 100644 --- a/src/doc.c +++ b/src/doc.c @@ -127,7 +127,10 @@ get_doc_string (Lisp_Object filepos, bool unibyte) else return Qnil; - EMACS_INT position = XFIXNUM (pos); + /* We used to emit negative positions for 'user variables' (whose doc + strings started with an asterisk); take the absolute value for + compatibility with bytecode from Emacs <29. */ + EMACS_INT position = eabs (XFIXNUM (pos)); if (!STRINGP (dir)) return Qnil; commit c7f6da7a4141a9f3492b8dbb0c1de710bd4757fa Author: Stefan Kangas Date: Fri Jan 24 00:16:08 2025 +0100 Don't use negative positions for docstrings These were used for user-variables (doc starts with a '*'), but we don't use that convention any more. On my machine, there are no docstrings starting with a '*' in etc/DOC. * src/doc.c (Fsnarf_documentation): Never use negative positions. (get_doc_string): Don't use eabs; position must now be positive, and all callers are verified to do that. diff --git a/src/doc.c b/src/doc.c index d16d3d5186e..0ce1274fe12 100644 --- a/src/doc.c +++ b/src/doc.c @@ -96,9 +96,6 @@ close_file_unwind_android_fd (void *ptr) If it is an integer, use that position in the standard DOC file. If it is (FILE . INTEGER), use FILE as the file name and INTEGER as the position in that file. - But if INTEGER is negative, make it positive. - (A negative integer is used for user variables, so we can distinguish - them without actually fetching the doc string.) If the location does not point to the beginning of a docstring (e.g. because the file has been modified and the location is stale), @@ -130,7 +127,7 @@ get_doc_string (Lisp_Object filepos, bool unibyte) else return Qnil; - EMACS_INT position = eabs (XFIXNUM (pos)); + EMACS_INT position = XFIXNUM (pos); if (!STRINGP (dir)) return Qnil; @@ -192,7 +189,7 @@ get_doc_string (Lisp_Object filepos, bool unibyte) P points beyond the data just read. */ p = get_doc_string_buffer; - while (1) + while (true) { ptrdiff_t space_left = (get_doc_string_buffer_size - 1 - (p - get_doc_string_buffer)); @@ -508,10 +505,7 @@ That file is found in `../etc' now; later, when the dumped Emacs is run, the same file name is found in the `doc-directory'. */) (Lisp_Object filename) { - doc_fd fd; char buf[1024 + 1]; - int filled; - EMACS_INT pos; Lisp_Object sym; char *p, *name; char const *dirname; @@ -555,7 +549,7 @@ the same file name is found in the `doc-directory'. */) Vbuild_files = Fpurecopy (Vbuild_files); } - fd = doc_open (name, O_RDONLY, 0); + doc_fd fd = doc_open (name, O_RDONLY, 0); if (!doc_fd_p (fd)) { int open_errno = errno; @@ -568,8 +562,8 @@ the same file name is found in the `doc-directory'. */) record_unwind_protect_ptr (close_file_unwind_android_fd, &fd); #endif /* !USE_ANDROID_ASSETS */ Vdoc_file_name = filename; - filled = 0; - pos = 0; + int filled = 0; + EMACS_INT pos = 0; while (true) { if (filled < 512) @@ -609,15 +603,13 @@ the same file name is found in the `doc-directory'. */) /* Attach a docstring to a variable? */ if (p[1] == 'V') { - /* Install file-position as variable-documentation property - and make it negative for a user-variable - (doc starts with a `*'). */ + /* Install file-position as variable-documentation + property. */ if ((!NILP (Fboundp (sym)) || !NILP (Fmemq (sym, delayed_init))) && strncmp (end, "\nSKIP", 5)) Fput (sym, Qvariable_documentation, - make_fixnum ((pos + end + 1 - buf) - * (end[1] == '*' ? -1 : 1))); + make_fixnum (pos + end + 1 - buf)); } /* Attach a docstring to a function? */ commit ed5067e689a5e38795d5c27c5a688886d259a298 Author: Pip Cet Date: Wed Jan 22 19:08:02 2025 +0000 Fix GC bug causing incorrect 'format' output (Bug#75754) This fixes the correctness bug discovered in bug#75754, but not the performance issue or excessive stack usage. * src/editfns.c (styled_format): Split 'info' array into two arrays, one of them allocated via SAFE_ALLOCA_LISP for GC protection. diff --git a/src/editfns.c b/src/editfns.c index 8a5fb673fe7..4ba356d627c 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -3431,10 +3431,6 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) /* Information recorded for each format spec. */ struct info { - /* The corresponding argument, converted to string if conversion - was needed. */ - Lisp_Object argument; - /* The start and end bytepos in the output string. */ ptrdiff_t start, end; @@ -3461,6 +3457,10 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) || SIZE_MAX < alloca_size) memory_full (SIZE_MAX); info = SAFE_ALLOCA (alloca_size); + /* One argument belonging to each spec; but needs to be allocated + separately so GC doesn't free the strings (bug#75754). */ + Lisp_Object *spec_arguments; + SAFE_ALLOCA_LISP (spec_arguments, nspec_bound); /* discarded[I] is 1 if byte I of the format string was not copied into the output. It is 2 if byte I was not the first byte of its character. */ @@ -3610,14 +3610,15 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) if (! (n < nargs)) error ("Not enough arguments for format string"); - struct info *spec = &info[ispec++]; + ptrdiff_t spec_index = ispec++; + struct info *spec = &info[spec_index]; if (nspec < ispec) { - spec->argument = args[n]; + spec_arguments[spec_index] = args[n]; spec->intervals = false; nspec = ispec; } - Lisp_Object arg = spec->argument; + Lisp_Object arg = spec_arguments[spec_index]; /* For 'S', prin1 the argument, and then treat like 's'. For 's', princ any argument that is not a string or @@ -3630,7 +3631,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) if (EQ (arg, args[n])) { Lisp_Object noescape = conversion == 'S' ? Qnil : Qt; - spec->argument = arg = Fprin1_to_string (arg, noescape, Qnil); + spec_arguments[spec_index] = arg = Fprin1_to_string (arg, noescape, Qnil); if (STRING_MULTIBYTE (arg) && ! multibyte) { multibyte = true; @@ -3648,7 +3649,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) multibyte = true; goto retry; } - spec->argument = arg = Fchar_to_string (arg); + spec_arguments[spec_index] = arg = Fchar_to_string (arg); } if (!EQ (arg, args[n])) @@ -3658,7 +3659,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) if (SYMBOLP (arg)) { - spec->argument = arg = SYMBOL_NAME (arg); + spec_arguments[spec_index] = arg = SYMBOL_NAME (arg); if (STRING_MULTIBYTE (arg) && ! multibyte) { multibyte = true; @@ -4303,9 +4304,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) for (ptrdiff_t i = 0; i < nspec; i++) if (info[i].intervals) { - len = make_fixnum (SCHARS (info[i].argument)); + len = make_fixnum (SCHARS (spec_arguments[i])); Lisp_Object new_len = make_fixnum (info[i].end - info[i].start); - props = text_property_list (info[i].argument, + props = text_property_list (spec_arguments[i], make_fixnum (0), len, Qnil); props = extend_property_ranges (props, len, new_len); /* If successive arguments have properties, be sure that commit 990b0811adefb4b792d36797540e5773791437f9 Author: Stefan Kangas Date: Thu Jan 23 18:45:14 2025 +0100 Simplify Fdocumentation and Fdocumentation_property * src/doc.c (Fdocumentation, Fdocumentation_property): Simplify; reread_doc_file always returns true so just assume that. (reread_doc_file): Change return type to void. diff --git a/src/doc.c b/src/doc.c index 1c5906de9dc..d16d3d5186e 100644 --- a/src/doc.c +++ b/src/doc.c @@ -307,15 +307,13 @@ Invalid data in documentation file -- %c followed by code %03o", } } -static bool +static void reread_doc_file (Lisp_Object file) { if (NILP (file)) Fsnarf_documentation (Vdoc_file_name); else save_match_data_load (file, Qt, Qt, Qt, Qnil); - - return 1; } DEFUN ("documentation-stringp", Fdocumentation_stringp, Sdocumentation_stringp, @@ -341,7 +339,7 @@ string is passed through `substitute-command-keys'. */) Lisp_Object doc; bool try_reload = true; - documentation: + retry: doc = Qnil; @@ -366,20 +364,15 @@ string is passed through `substitute-command-keys'. */) doc = Qnil; if (FIXNUMP (doc) || CONSP (doc)) { - Lisp_Object tem; - tem = get_doc_string (doc, 0); + Lisp_Object tem = get_doc_string (doc, 0); if (NILP (tem) && try_reload) { /* The file is newer, we need to reset the pointers. */ - try_reload = reread_doc_file (Fcar_safe (doc)); - if (try_reload) - { - try_reload = false; - goto documentation; - } + reread_doc_file (Fcar_safe (doc)); + try_reload = false; + goto retry; } - else - doc = tem; + doc = tem; } if (NILP (raw)) @@ -420,7 +413,7 @@ aren't strings. */) bool try_reload = true; Lisp_Object tem; - documentation_property: + retry: tem = Fget (symbol, prop); @@ -446,12 +439,9 @@ aren't strings. */) if (NILP (tem) && try_reload) { /* The file is newer, we need to reset the pointers. */ - try_reload = reread_doc_file (Fcar_safe (doc)); - if (try_reload) - { - try_reload = false; - goto documentation_property; - } + reread_doc_file (Fcar_safe (doc)); + try_reload = false; + goto retry; } } else if (!STRINGP (tem)) commit c888e726ca9092fedd98e80e40c28b0fa54a34be Author: João Távora Date: Thu Jan 23 11:20:38 2025 +0000 Eglot: skip Tramp tests except on Emacs 28+ * test/lisp/progmodes/eglot-tests.el (eglot--call-with-tramp-test): Fix diff --git a/test/lisp/progmodes/eglot-tests.el b/test/lisp/progmodes/eglot-tests.el index cc269abea08..eec076da723 100644 --- a/test/lisp/progmodes/eglot-tests.el +++ b/test/lisp/progmodes/eglot-tests.el @@ -1421,6 +1421,8 @@ GUESSED-MAJOR-MODES-SYM are bound to the useful return values of (defvar tramp-histfile-override) (defun eglot--call-with-tramp-test (fn) + (unless (>= emacs-major-version 28) + (ert-skip "Tramp tests only work reliably on Emacs 28+")) ;; Set up a Tramp method that’s just a shell so the remote host is ;; really just the local host. (let* ((tramp-remote-path (cons 'tramp-own-remote-path commit d83d090de1127d6e88e4ff33a617d8621a85a8cd Author: Gerd Möllmann Date: Thu Jan 23 15:30:30 2025 +0100 Handle tty menus overlapping child frames * src/dispnew.c (frame_pos_abs, is_frame_ancestor): Make externally visible. * src/dispextern.h: Declare above functions. * src/term.c (mouse_get_xy): Handle mouse movement over child frames. diff --git a/src/dispextern.h b/src/dispextern.h index ccf0aebd7c6..1060895d0f4 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3958,6 +3958,8 @@ void combine_updates (Lisp_Object root_frames); void combine_updates_for_frame (struct frame *f, bool inhibit_id_p); void tty_raise_lower_frame (struct frame *f, bool raise); int max_child_z_order (struct frame *parent); +void frame_pos_abs (struct frame *f, int *x, int *y); +bool is_frame_ancestor (struct frame *f1, struct frame *f2); INLINE_HEADER_END diff --git a/src/dispnew.c b/src/dispnew.c index 23ef5ff699b..9726bf70660 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3315,7 +3315,7 @@ rect_intersect (struct rect *r, struct rect r1, struct rect r2) /* Return the absolute position of frame F in *X and *Y. */ -static void +void frame_pos_abs (struct frame *f, int *x, int *y) { *x = *y = 0; @@ -3355,7 +3355,7 @@ max_child_z_order (struct frame *parent) /* Return true if F1 is an ancestor of F2. */ -static bool +bool is_frame_ancestor (struct frame *f1, struct frame *f2) { for (struct frame *f = FRAME_PARENT_FRAME (f2); f; f = FRAME_PARENT_FRAME (f)) diff --git a/src/term.c b/src/term.c index f7d3e58a465..4ae9c373888 100644 --- a/src/term.c +++ b/src/term.c @@ -2990,19 +2990,16 @@ tty_menu_calc_size (tty_menu *menu, int *width, int *height) static void mouse_get_xy (int *x, int *y) { - Lisp_Object lmx = Qnil, lmy = Qnil; Lisp_Object mouse = mouse_position (tty_menu_calls_mouse_position_function); - if (EQ (selected_frame, XCAR (mouse))) - { - lmx = XCAR (XCDR (mouse)); - lmy = XCDR (XCDR (mouse)); - } - - if (!NILP (lmx)) + struct frame *f = XFRAME (XCAR (mouse)); + struct frame *sf = SELECTED_FRAME (); + if (f == sf || is_frame_ancestor (sf, f)) { - *x = XFIXNUM (lmx); - *y = XFIXNUM (lmy); + int fx, fy; + frame_pos_abs (f, &fx, &fy); + *x = fx + XFIXNUM (XCAR (XCDR (mouse))); + *y = fy + XFIXNUM (XCDR (XCDR (mouse))); } } commit da3b93ff9658481fa81a1dbd49618ed8792f9f3b Author: Robert Pluim Date: Thu Jan 23 13:27:40 2025 +0100 ; * lisp/emacs-lisp/shortdoc.el (map): Fix copy'n'pasto. diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el index 321ff22a12d..cc9971b232f 100644 --- a/lisp/emacs-lisp/shortdoc.el +++ b/lisp/emacs-lisp/shortdoc.el @@ -240,10 +240,10 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'), :eval (map-keys #s(hash-table data (bar 1 foo 2 baz 3)))) (map-values :args (map) - :eval (map-keys (list 'bar 1 'foo 2 'baz 3)) - :eval (map-keys (list '(bar . 1) '(foo . 2) '(baz . 3))) - :eval (map-keys [bar foo baz]) - :eval (map-keys #s(hash-table data (bar 1 foo 2 baz 3)))) + :eval (map-values (list 'bar 1 'foo 2 'baz 3)) + :eval (map-values (list '(bar . 1) '(foo . 2) '(baz . 3))) + :eval (map-values [bar foo baz]) + :eval (map-values #s(hash-table data (bar 1 foo 2 baz 3)))) (map-pairs :eval (map-pairs (list 'bar 1 'foo 2 'baz 3)) :eval (map-pairs (list '(bar . 1) '(foo . 2) '(baz . 3))) commit 67480c159ed3a4b3c8a93f6dbe0317617cf6ee26 Author: Robert Pluim Date: Thu Jan 23 11:17:12 2025 +0100 Add shortdoc for map.el functions * lisp/emacs-lisp/shortdoc.el (map): New shortdoc group. diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el index 230df47821c..321ff22a12d 100644 --- a/lisp/emacs-lisp/shortdoc.el +++ b/lisp/emacs-lisp/shortdoc.el @@ -174,6 +174,137 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'), (if (eq .rose 'red) .lily))))) +(define-short-documentation-group map + "Map Basics" + (mapp + :eval (mapp (list 'bar 1 'foo 2 'baz 3)) + :eval (mapp (list '(bar . 1) '(foo . 2) '(baz . 3))) + :eval (mapp [bar foo baz]) + :eval (mapp "this is a string") + :eval (mapp #s(hash-table data (bar 1 foo 2 baz 3))) + :eval (mapp '()) + :eval (mapp nil) + :eval (mapp (make-char-table 'shortdoc-test))) + (map-empty-p + :args (map) + :eval (map-empty-p nil) + :eval (map-empty-p []) + :eval (map-empty-p '())) + (map-elt + :args (map key) + :eval (map-elt (list 'bar 1 'foo 2 'baz 3) 'foo) + :eval (map-elt (list '(bar . 1) '(foo . 2) '(baz . 3)) 'foo) + :eval (map-elt [bar foo baz] 1) + :eval (map-elt #s(hash-table data (bar 1 foo 2 baz 3)) 'foo)) + (map-contains-key + :args (map key) + :eval (map-contains-key (list 'bar 1 'foo 2 'baz 3) 'foo) + :eval (map-contains-key (list '(bar . 1) '(foo . 2) '(baz . 3)) 'foo) + :eval (map-contains-key [bar foo baz] 1) + :eval (map-contains-key #s(hash-table data (bar 1 foo 2 baz 3)) 'foo)) + (map-put! + (map key value) + :eval +"(let ((map (list 'bar 1 'baz 3))) + (map-put! map 'foo 2) + map)" +;; This signals map-not-inplace when used in shortdoc.el :-( +;; :eval +;; "(let ((map (list '(bar . 1) '(baz . 3)))) +;; (map-put! map 'foo 2) +;; map)" + :eval +"(let ((map [bar bot baz])) + (map-put! map 1 'foo) + map)" + :eval +"(let ((map #s(hash-table data (bar 1 baz 3)))) + (map-put! map 'foo 2) + map)") + (map-insert + :args (map key value) + :eval (map-insert (list 'bar 1 'baz 3 'foo 7) 'foo 2) + :eval (map-insert (list '(bar . 1) '(baz . 3) '(foo . 7)) 'foo 2) + :eval (map-insert [bar bot baz] 1 'foo) + :eval (map-insert #s(hash-table data (bar 1 baz 3 foo 7)) 'foo 2)) + (map-delete + :args (map key) + :eval (map-delete (list 'bar 1 'foo 2 'baz 3) 'foo) + :eval (map-delete (list '(bar . 1) '(foo . 2) '(baz . 3)) 'foo) + :eval (map-delete [bar foo baz] 1) + :eval (map-delete #s(hash-table data (bar 1 foo 2 baz 3)) 'foo)) + (map-keys + :eval (map-keys (list 'bar 1 'foo 2 'baz 3)) + :eval (map-keys (list '(bar . 1) '(foo . 2) '(baz . 3))) + :eval (map-keys [bar foo baz]) + :eval (map-keys #s(hash-table data (bar 1 foo 2 baz 3)))) + (map-values + :args (map) + :eval (map-keys (list 'bar 1 'foo 2 'baz 3)) + :eval (map-keys (list '(bar . 1) '(foo . 2) '(baz . 3))) + :eval (map-keys [bar foo baz]) + :eval (map-keys #s(hash-table data (bar 1 foo 2 baz 3)))) + (map-pairs + :eval (map-pairs (list 'bar 1 'foo 2 'baz 3)) + :eval (map-pairs (list '(bar . 1) '(foo . 2) '(baz . 3))) + :eval (map-pairs [bar foo baz]) + :eval (map-pairs #s(hash-table data (bar 1 foo 2 baz 3)))) + (map-length + :args (map) + :eval (map-length (list 'bar 1 'foo 2 'baz 3)) + :eval (map-length (list '(bar . 1) '(foo . 2) '(baz . 3))) + :eval (map-length [bar foo baz]) + :eval (map-length #s(hash-table data (bar 1 foo 2 baz 3)))) + (map-copy + :args (map) + :eval (map-copy (list 'bar 1 'foo 2 'baz 3)) + :eval (map-copy (list '(bar . 1) '(foo . 2) '(baz . 3))) + :eval (map-copy [bar foo baz]) + :eval (map-copy #s(hash-table data (bar 1 foo 2 baz 3)))) + "Doing things to maps and their contents" + (map-apply + :args (function map) + :eval (map-apply #'+ (list '(1 . 2) '(3 . 4)))) + (map-do + :args (function map) + :eval +"(let ((map (list '(1 . 1) '(2 . 3))) + acc) + (map-do (lambda (k v) (push (+ k v) acc)) map) + (nreverse acc))") + (map-keys-apply + :eval (map-keys-apply #'1+ (list '(1 . 2) '(3 . 4)))) + (map-values-apply + :args (function map) + :eval (map-values-apply #'1+ (list '(1 . 2) '(3 . 4)))) + (map-filter + :eval (map-filter (lambda (k _) (cl-oddp k)) (list '(1 . 2) '(4 . 6))) + :eval (map-filter (lambda (k v) (cl-evenp (+ k v))) (list '(1 . 2) '(4 . 6)))) + (map-remove + :eval (map-remove (lambda (k _) (cl-oddp k)) (list '(1 . 2) '(4 . 6))) + :eval (map-remove (lambda (k v) (cl-evenp (+ k v))) (list '(1 . 2) '(4 . 6)))) + (map-some + :eval (map-some (lambda (k _) (cl-oddp k)) (list '(1 . 2) '(4 . 6))) + :eval (map-some (lambda (k v) (cl-evenp (+ k v))) (list '(1 . 2) '(4 . 6)))) + (map-every-p + :eval (map-every-p (lambda (k _) (cl-oddp k)) (list '(1 . 2) '(4 . 6))) + :eval (map-every-p (lambda (k v) (cl-evenp (+ k v))) (list '(1 . 3) '(4 . 6)))) + "Combining and changing maps" + (map-merge + :eval (map-merge 'alist '(1 2 3 4) #s(hash-table data (5 6 7 8))) + :eval (map-merge 'list '(1 2 3 4) #s(hash-table data (5 6 7 8))) + :eval (map-merge 'plist '(1 2 3 4) #s(hash-table data (5 6 7 8))) + :eval (map-merge 'hash-table '(1 2 3 4) #s(hash-table data (5 6 7 8)))) + (map-merge-with + :eval (map-merge-with 'alist #'max '(1 2 3 4) #s(hash-table data (1 1 3 5))) + :eval (map-merge-with 'alist #'min '(1 2 3 4) #s(hash-table data (1 1 3 5))) + :eval (map-merge-with 'hash-table #'min '(1 2 3 4) #s(hash-table data (1 1 3 5)))) + (map-into + :args (map type) + :eval (map-into #s(hash-table data '(5 6 7 8)) 'list) + :eval (map-into '((5 . 6) (7 . 8)) 'plist) + :eval (map-into '((5 . 6) (7 . 8)) 'hash-table))) + (define-short-documentation-group string "Making Strings" (make-string commit 076cd69fc2e6edcc1d667266f0cf2f7743de0df5 Author: Gerd Möllmann Date: Thu Jan 23 11:07:13 2025 +0100 Don't forget setting the top frame if not switching root frames * src/frame.c (do_switch_frame): Make sure to set top frame in all cases. diff --git a/src/frame.c b/src/frame.c index 258bf08788f..c77b016b709 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1808,6 +1808,11 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor FrameRows (tty) = FRAME_TOTAL_LINES (f); } } + else + { + SET_FRAME_VISIBLE (f, true); + tty->top_frame = frame; + } } sf->select_mini_window_flag = MINI_WINDOW_P (XWINDOW (sf->selected_window));