JohnCoates / Aerial

Apple TV Aerial Screensaver for Mac
MIT License
20.75k stars 1.05k forks source link

Sonoma 14.1 com.apple.screensaver.willstop unreliable #1339

Open xmddmx opened 8 months ago

xmddmx commented 8 months ago

This is related to our technique of using exit(0) upon receipt of the com.apple.sceensaver.willstop notification, see https://github.com/JohnCoates/Aerial/issues/1305#issuecomment-1680853387

I'm finding than in 14.1 beta 3, repeated starting / stopping of a screensaver using a hotcorner (with "require password" turned off) and exiting with a mouse click, I can sometimes get into a state where the screensaver is still running, but no longer on screen.

Detailed logging shows that the OS is simply not sending the com.apple.screensaver.willstop notification.

My guess is that with a rapid starting / stopping of screensavers, the OS gets confused (perhaps by launching 2 or more instances?) and so the notification is never received.

I'm trying to think of some way to detect this situation, since having an orphaned screensaver processing running in the background is not good.

I wonder: is it possible that the legacyScreenSaver process is going into the mode where the process name changes to legacyScreenSaver (Wallpaper) ? If so, is there any way to detect this process name?

glouel commented 8 months ago

I can confirm I had noticed something like that, my guess was like yours, whatever they use for "bridging" to the wallpaper is still there (maybe our friend WallpaperAgent) and is messing up subsequent relaunches because some events didn't happen fully (I would guess the full transition to slowed down video + conversion to a fixed wallpaper). Waiting 10s before tries works fine.

What I noticed is that things do clear up though on subsequent proper launch/exit (so if you have 2 screens, you have 2 instances remaining for a bit, you launch again, you get 4, but the 4 will quit properly).

One of "those things" 🤷

xmddmx commented 8 months ago

After hacking around, I realized that what I really need is the ability to ignore mouse events while the lock screen password prompt is up.

I tried a bunch of ideas, and the closest I got was detecting if the coreautha process had a window open:

    if let info = CGWindowListCopyWindowInfo(.optionAll,kCGNullWindowID) as? [[ String : Any]] {
        for dict in info {
            let owner    = dict["kCGWindowOwnerName"] as? String ?? "none"
            if (owner == "coreautha") {
                NSLog("\(dict)")
            }
   }

Unfortunately in Sonoma, the 'coreautha' window is opened at the "Lock screen after ..." timeout, and there is no way to tell from the data if it's visible or not visible.

Regardless of whether the password prompt is visible or not, I always see something like this:

[
  "kCGWindowSharingState": 0, 
  "kCGWindowLayer": 1000, 
  "kCGWindowNumber": 518, 
  "kCGWindowOwnerName": coreautha, 
  "kCGWindowOwnerPID": 706, 
  "kCGWindowMemoryUsage": 2160, 
  "kCGWindowAlpha": 1, 
  "kCGWindowBounds": {
    Height = 0;
    Width = 0;
    X = 0;
    Y = 0;
    }, 
  "kCGWindowStoreType": 1]

the bounds are always 0,0,0,0 and Alpha is always 1, regardless of whether the lock screen password dialog is on or off...

glouel commented 8 months ago

Interesting, did you try looking for "com.apple.screenIsUnlocked" in distributed notifications ? I believe this is what you seek.

Edit : This is what I used to use before, I changed it to willstop for "some reason" that I can't quite remember right now.

Side note, the 0,0 thing kinda makes me think of the good old days of absolute full screen modes on other OSes. They seem to replicate that a bit here with making whatever the window is believe it's owning the entire screen, but that model fails hard with multiple monitors.

xmddmx commented 8 months ago

com.apple.screenIsUnlocked : my screensaver process is definitely not receiving those in Sonoma at all (although I can see they are being sent at the os level)

-[SessionAgentNotificationCenter sendDistributedNotification:forUserID:] | sendDistributedNotification: com.apple.screenIsUnlocked, with userID:501

I'm wondering if there's some way to dig into the coreautha (or loginwindow) processes and figure out if they are frontmost or not sleeping or similar...