Stop display link when window is occluded (#7511)

Antonio Scandurra and Conrad created

Release Notes:

- Fixed a bug that caused the window to become unresponsive after
foregrounding.

---------

Co-authored-by: Conrad <conrad@zed.dev>

Change summary

crates/gpui/src/platform/mac/window.rs | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)

Detailed changes

crates/gpui/src/platform/mac/window.rs 🔗

@@ -12,7 +12,7 @@ use cocoa::{
         CGPoint, NSApplication, NSBackingStoreBuffered, NSEventModifierFlags,
         NSFilenamesPboardType, NSPasteboard, NSScreen, NSView, NSViewHeightSizable,
         NSViewWidthSizable, NSWindow, NSWindowButton, NSWindowCollectionBehavior,
-        NSWindowStyleMask, NSWindowTitleVisibility,
+        NSWindowOcclusionState, NSWindowStyleMask, NSWindowTitleVisibility,
     },
     base::{id, nil},
     foundation::{
@@ -249,6 +249,10 @@ unsafe fn build_window_class(name: &'static str, superclass: &Class) -> *const C
         sel!(windowDidResize:),
         window_did_resize as extern "C" fn(&Object, Sel, id),
     );
+    decl.add_method(
+        sel!(windowDidChangeOcclusionState:),
+        window_did_change_occlusion_state as extern "C" fn(&Object, Sel, id),
+    );
     decl.add_method(
         sel!(windowWillEnterFullScreen:),
         window_will_enter_fullscreen as extern "C" fn(&Object, Sel, id),
@@ -530,14 +534,12 @@ impl MacWindow {
             let native_view = NSView::init(native_view);
             assert!(!native_view.is_null());
 
-            let display_link = start_display_link(native_window.screen(), native_view);
-
             let window = Self(Arc::new(Mutex::new(MacWindowState {
                 handle,
                 executor,
                 native_window,
                 native_view: NonNull::new_unchecked(native_view),
-                display_link,
+                display_link: nil,
                 renderer: MetalRenderer::new(instance_buffer_pool),
                 kind: options.kind,
                 request_frame_callback: None,
@@ -1332,6 +1334,23 @@ extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
     }
 }
 
+extern "C" fn window_did_change_occlusion_state(this: &Object, _: Sel, _: id) {
+    let window_state = unsafe { get_window_state(this) };
+    let mut lock = window_state.lock();
+    unsafe {
+        if lock
+            .native_window
+            .occlusionState()
+            .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible)
+        {
+            lock.display_link =
+                start_display_link(lock.native_window.screen(), lock.native_view.as_ptr());
+        } else {
+            lock.display_link = nil;
+        }
+    }
+}
+
 extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) {
     let window_state = unsafe { get_window_state(this) };
     window_state.as_ref().lock().move_traffic_light();