Subject: bug#16097: [PATCH] Treat windows on other spaces as not visible in Cocoa

From: Robert Pluim <[email-masked]>
Date: Fri, 28 Jan 2022 09:17:24 +0100

>>>>> On Thu, 27 Jan 2022 20:58:11 +0000, Alan Third <[email-masked]> said:

    Alan> On Thu, Jan 27, 2022 at 12:06:36PM +0100, Robert Pluim wrote:
    >> >>>>> On Wed, 26 Jan 2022 17:46:15 +0100, Lars Ingebrigtsen <[email-masked]> said:
    >> 
    Lars> David Benjamin <[email-masked]> writes:
    >> >> Here's a patch for something that's been bugging me. This makes Cmd-`
    >> >> cycle through only the current space's windows, which is consistent
    >> >> with other programs on OS X. It also matches the behavior of
    >> >> other-frame on X11 for window managers that implement virtual desktops
    >> >> by mapping and unmapping windows. The patch is attached.
    >> 
    Lars> Perhaps Alan has a comment here; added to the CCs.
    >> 
    >> Please let's apply this. Please. Pretty please. Pretty please with sugar on
    >> top. Please.
    >> 
    >> Iʼve rebased it to master and attach it here.
    >> 
    >> Did I mention I like it?

    Alan> I'm afraid I don't much. It looks like the updateVisibility method
    Alan> doesn't actually do enough to replace the windowDidBecomeKey method.

Thatʼs an artifact of me screwing up the patch, I think. But it
probably needs updating anyway, as Po pointed out.

    Alan> It also needs a good clean. For example there's a hunk that appears to
    Alan> just be removing a single blank line and most of the #ifdef's are
    Alan> redundant. I guess some of the weirdness in it is just because it's so
    Alan> old.

Sorry, I messed up the rebase. The attached should be better.

>From a7054fc3d66b48161b562a8715730c002994dc4a Mon Sep 17 00:00:00 2001
From: David Benjamin <[email-masked]>
Date: Fri, 28 Jan 2022 09:11:09 +0100
Subject: [PATCH] Make other-frame cycle on current space only (nsterm)
To: [email-masked]

In nsterm, update frame visibility on space change and application
hide/unhide. This makes other-frame cycle through windows correctly.

* nsterm.m (updateVisibility:): New function from code in
windowDidMiniaturize and windowDidDeminiaturize.
(windowDidMiniaturize:, windowDidDeminiaturize:): Call
updateVisibility.
(initFrameFromEmacs:): Register for notifications of application
hide/unhide and, on Cocoa, space changes.
(dealloc): Clean up notifications.
* nsterm.h (EmacsView): Declaration for updateVisibility.
---
 src/nsterm.h |  1 +
 src/nsterm.m | 92 ++++++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 76 insertions(+), 17 deletions(-)

diff --git a/src/nsterm.h b/src/nsterm.h
index f027646123..db4e75641b 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -481,6 +481,7 @@ #define NSTRACE_UNSILENCE()
 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
 - (void) updateCollectionBehavior;
 #endif
+- (void) updateVisibility: (NSNotification *)notification;
 
 #ifdef NS_IMPL_GNUSTEP
 - (void)windowDidMove: (id)sender;
diff --git a/src/nsterm.m b/src/nsterm.m
index a3c7b55218..ce933e73eb 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -5959,6 +5959,22 @@ - (void)dealloc
 {
   NSTRACE ("[EmacsView dealloc]");
 
+  [[NSNotificationCenter defaultCenter]
+      removeObserver: self
+                name: NSApplicationDidHideNotification
+              object: nil];
+  [[NSNotificationCenter defaultCenter]
+      removeObserver: self
+                name: NSApplicationDidUnhideNotification
+              object: nil];
+#if defined(NS_IMPL_COCOA) && \
+  MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+  [[[NSWorkspace sharedWorkspace] notificationCenter]
+    removeObserver: self
+              name: NSWorkspaceActiveSpaceDidChangeNotification
+            object: nil];
+#endif /* NS_IMPL_COCOA && >= MAC_OS_X_VERSION_10_6 */
+
   /* Clear the view resize notification.  */
   [[NSNotificationCenter defaultCenter]
     removeObserver:self
@@ -7214,6 +7230,27 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f
   [NSApp registerServicesMenuSendTypes: ns_send_types
                            returnTypes: [NSArray array]];
 
+  /* Update visibility state on application hide and unhide. */
+  [[NSNotificationCenter defaultCenter]
+      addObserver: self
+         selector: @selector (updateVisibility:)
+             name: NSApplicationDidHideNotification
+           object: nil];
+  [[NSNotificationCenter defaultCenter]
+      addObserver: self
+         selector: @selector (updateVisibility:)
+             name: NSApplicationDidUnhideNotification
+           object: nil];
+
+#if defined(NS_IMPL_COCOA) && \
+  MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+  [[[NSWorkspace sharedWorkspace] notificationCenter]
+    addObserver: self
+       selector: @selector (updateVisibility:)
+           name: NSWorkspaceActiveSpaceDidChangeNotification
+         object: nil];
+#endif /* NS_IMPL_COCOA && >= MAC_OS_X_VERSION_10_6 */
+
   ns_window_num++;
   return self;
 }
@@ -7383,18 +7420,7 @@ - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
 - (void)windowDidDeminiaturize: sender
 {
   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
-  if (!emacsframe->output_data.ns)
-    return;
-
-  SET_FRAME_ICONIFIED (emacsframe, 0);
-  SET_FRAME_VISIBLE (emacsframe, 1);
-  windows_or_buffers_changed = 63;
-
-  if (emacs_event)
-    {
-      emacs_event->kind = DEICONIFY_EVENT;
-      EV_TRAILER ((id)nil);
-    }
+  [self updateVisibility:nil];
 }

@@ -7415,16 +7441,48 @@ - (void)windowDidExpose: sender
 - (void)windowDidMiniaturize: sender
 {
   NSTRACE ("[EmacsView windowDidMiniaturize:]");
+  [self updateVisibility:nil];
+}
+
+- (void)updateVisibility: (NSNotification *)notification
+{
+  NSTRACE (updateVisibility);
+
   if (!emacsframe->output_data.ns)
     return;
 
-  SET_FRAME_ICONIFIED (emacsframe, 1);
-  SET_FRAME_VISIBLE (emacsframe, 0);
+  NSWindow *win = [self window];
+  BOOL on_active_space = YES;
+  if ([win respondsToSelector: @selector (isOnActiveSpace)])
+    on_active_space = [win isOnActiveSpace];
+  if (on_active_space && [win isVisible])
+    {
+      if (FRAME_VISIBLE_P (emacsframe) && !FRAME_ICONIFIED_P (emacsframe))
+        return;
 
-  if (emacs_event)
+      SET_FRAME_ICONIFIED (emacsframe, 0);
+      SET_FRAME_VISIBLE (emacsframe, 1);
+      windows_or_buffers_changed = 63;
+
+      if (emacs_event)
+        {
+          emacs_event->kind = DEICONIFY_EVENT;
+          EV_TRAILER ((id)nil);
+        }
+    }
+  else
     {
-      emacs_event->kind = ICONIFY_EVENT;
-      EV_TRAILER ((id)nil);
+      if (!FRAME_VISIBLE_P (emacsframe) && FRAME_ICONIFIED_P (emacsframe))
+        return;
+
+      SET_FRAME_ICONIFIED (emacsframe, 1);
+      SET_FRAME_VISIBLE (emacsframe, 0);
+
+      if (emacs_event)
+        {
+          emacs_event->kind = ICONIFY_EVENT;
+          EV_TRAILER ((id)nil);
+        }
     }
 }
 
-- 
2.34.0

Robert
--