From 3801c09ae22fe5bc0bf42546b2747824cb9fe0b6 Mon Sep 17 00:00:00 2001 From: Andrea Alberti Date: Fri, 29 May 2026 10:42:47 +0200 Subject: [PATCH] Don't resurrect invisible child frames when rebuilding parent links On the NS port, -[EmacsWindow setParentChildRelationships] reattaches every child frame to its parent via -addChildWindow:ordered:, which also orders the child window onto the screen. This runs whenever the parent/child relationships are rebuilt, e.g., when entering non-native fullscreen, which allocates a fresh EmacsWindow whose initializer rebuilds the relationships. A child frame that Emacs had made invisible (e.g. a corfu/company completion popup) was thereby brought back as a stale, non-responsive child frame. Emacs never repaints to clear it because frame_redisplay_p trusts FRAME_VISIBLE_P on the NS port and avoids dealing with the child frame when it is marked as invisible. Native fullscreen does not trigger this: -toggleFullScreen: hands off to AppKit without allocating a new window, so the rebuild never runs. A hidden child frame is normally detached from its parent already: Emacs hides it with -orderOut: (ns_make_frame_invisible), which per Apple's documentation removes a child window from its parent before ordering it out. The fix is therefore not to re-attach a child while it is invisible; ns_make_frame_visible already reinstates the parent/child link when the frame is shown again. * src/nsterm.m ([EmacsWindow setParentChildRelationships]): Only re-attach a child window when the frame is marked visible. (ns_make_frame_visible): Explain, with a reference to Apple's documentation, why the parent/child link must be reinstated on show. --- src/nsterm.m | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/nsterm.m b/src/nsterm.m index 2507053f3a1..f4de0a76c0a 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1651,8 +1651,13 @@ -(void)remove unblock_input (); } - /* Making a frame invisible seems to break the parent->child - relationship, so reinstate it. */ + /* A child window cannot remain attached while hidden. Per Apple's + documentation, "Calling orderOut(_:) on a child window causes the + window to be removed from its parent window before being removed" + (https://developer.apple.com/documentation/appkit/nswindow/orderout(_:)), + and ns_make_frame_invisible hides the frame with -orderOut:. The + parent->child relationship is therefore broken while invisible, so + reinstate it now that we are making the frame visible again. */ if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL) { block_input (); @@ -9979,8 +9984,15 @@ - (void)setParentChildRelationships [ourView toggleFullScreen:self]; #endif - [parentWindow addChildWindow:self - ordered:NSWindowAbove]; + /* -addChildWindow: also orders the child window onto the screen, so + attaching a child frame Emacs considers invisible is what + resurrects a dismissed completion popup (corfu, company-box, ...) + when relationships are rebuilt. Only attach a visible child; a + hidden one is re-attached by ns_make_frame_visible when it is + shown again. */ + if (FRAME_VISIBLE_P (ourFrame)) + [parentWindow addChildWindow:self + ordered:NSWindowAbove]; } /* Check our child windows are configured correctly. */