Memmon icon indicating copy to clipboard operation
Memmon copied to clipboard

Does not restore windows after sleep mode.

Open realrolfje opened this issue 2 years ago • 18 comments
trafficstars

When unplugging and plugging the second monitor, Memmon beautifully restores windows. But: When the lid is closed after unplugging the monitor, or the macbook hits sleep mode for being unattended for too long, the windows are not restored to the second monitor when plugging it in.

Reproduction:

  1. Drag monitors to second screen
  2. Unplug second screen (windows move to macbook screen)
  3. close macbook lid (or put macbook to sleep)
  4. open macbook lid
  5. plugin in second monitor

Result: Windows stay at macbook screen

Expected: Windows should pop back to second monitor

Thanks for this beautiful piece of software!

realrolfje avatar Jan 25 '23 08:01 realrolfje

I think I tested these steps (lid closing) during development and had no issues. I have not tested with sleep mode, I'll guess I have to try that and see if it triggers the described behavior. My access to external monitors is rare nowadays, so that test may take some time ... in the meantime, what macOS version are you using?

relikd avatar Jan 25 '23 10:01 relikd

Thanks for the fast response. Sorry for not being complete in versioning info. I am running memmon on an Apple M1 Pro 16" macbook with macOS 13.0.1 The external monitor is a Samsung ultra wide monitor, and it is plugged in through a usb-c cable which is connected to a port extender which is connected to the monitor, if that matters. My colleague has an Apple M1 14" with the same OS, and she experiences the same problem.

realrolfje avatar Jan 25 '23 11:01 realrolfje

Ah, I see, Ventura. I have another open issue related to Ventura, so I assume this is also Ventura related. I will look at both once I can upgrade my OS. I'll keep you posted 👍

relikd avatar Jan 25 '23 11:01 relikd

I'm seeing this issue in the latest version of Monterey as well (12.6.3).

MrFussyfont avatar Jan 31 '23 23:01 MrFussyfont

@MrFussyfont Thanks, thats something I can work with. I will run some tests as soon as possible and report back / fix the issue.

relikd avatar Feb 01 '23 08:02 relikd

Running Ventura 13.0.1 as well. Dual monitor setups aren't restored after sleep.

I'm going to poke around in Xcode later and see if this is some sort of race condition with the user getting identified at the Lock Screen before the second monitor is turned on, resetting the windows. Dunno if what I'm describing is even possible with the run-level of Memmon, but what I'm seeing sort of feels like a race condition.

wallyfoo avatar Feb 09 '23 09:02 wallyfoo

I am stuck. On my Mac the window restoration works as expected (without Memmon). This makes it impossible to play around with Memmon as I can not test my restore functionality. I hope @wallyfoo will find something. Or if someone knows a trick to bypass Apple's own window restoration?

relikd avatar Feb 20 '23 08:02 relikd

I think I found my issue: previously I had unchecked the setting "Displays have separate Spaces" under Mission Control in System Prefs, and now with that setting checked (which is the default), the Mac seems to be remembering window locations after sleep (without Memmon).

MrFussyfont avatar Feb 21 '23 15:02 MrFussyfont

Thanks, I will try to uncheck that to test if Memmon will be necessary again. But glad to hear this fixed it for you and Memmon isnt necessary anymore :)

If others (@wallyfoo, @realrolfje) can confirm that this option fixed the issue, I will add a notice to the Readme file.

relikd avatar Feb 21 '23 15:02 relikd

@MrFussyfont, Can you share your other settings in the Desktop & Dock preference besides? I have Displays have separate Spaces selected on my machine, and I'm still getting inconsistent results. Which OS version are you currently on? Perhaps you have received an update that I have yet to see...?

wallyfoo avatar Feb 21 '23 18:02 wallyfoo

I think memmon is still very much needed. Regardless of the "displays have separate spaces", I'd really like the windows to be in the place I left them when plugging in my external monitor.

realrolfje avatar Feb 22 '23 06:02 realrolfje

@wallyfoo, Monterey 12.6.3, M1 MacBook Air. One external display (LG 4K) connected by HDMI to Thunderbolt cable. The external is the "main" display (with the menu bar on top of it in Displays, though both actually show a menu bar due to the Mission Control setting) and not mirrored. Dock is positioned on the left and hidden until you mouse over. image

MrFussyfont avatar Feb 22 '23 14:02 MrFussyfont

Update: I've played around with a two-monitor setup today and identified the problem:

  1. Lets assume 2 monitors are attached (3 in total with macbook screen).
  2. detach monitor (3)
  3. Memmon automatically saves the current state for the three monitors
  4. Memmon automatically restores the state for a two-monitor setup.
  5. MacOS moves all windows from monitor (3) to monitor (2)
  6. attach monitor (3)
  7. Memmon saves the state for the two-monitor setup
  8. Memmon restores the state of the previous three-monitor setup (correct)
  9. detach monitor (2)
  10. Memmon saves the state for the three-monitor setup (correct)
  11. Memmon restores the state of the two-monitor setup (wrong!)

In step 11, the state of step 7 is restored. This is incorrect as it will try to move all windows to monitor (2) which was just disconnected. They appear randomly on the edge of the screen (it basically flips the content of monitor 2 and 3).

This behavior is with the current logic if prev-screen-count != new-screen-count. However, I've also tried to only save the current state if new-screen-count < prev-screen-count (to prevent the unnecessary step 7) but that didn't quite work out either. I have no solution yet, but I will look into it in the next few days. I'll probably have to read the monitor identifier for each display ... and somehow map it to the window position.

Anyway, I'll keep you posted.

relikd avatar Mar 13 '23 19:03 relikd

Played around a bit. I see no way around this issue. Actually, I am wondering why it did work in the first place ... I only get screen change events after a display was attached / detached (when it is already to late to store the window positions). Somehow it still works because the OS is too slow to update all windows and Memmon could read that state in the meantime. However, as soon as I add additional logic to distinguish between multi-monitor setups, the delay is too long and I get the already updated positions instead. This issue is even more relevant if your Macbook screen is the one that is being detached (closing the lid). The macbook lid updates are especially fast so that I cant even use the aforementioned delay. The window positions are just updated instantaneously. Unless I write a deamon which preemptively stores all positions, I dont see how to fix this. And honestly, I dont want to have a deamon running every second just to store the positions. That would burn the CPU for almost nothing.

relikd avatar Mar 20 '23 17:03 relikd

I had a bit of a play, too. As soon as I started adding a more complex data structure to remember the windows in relation to their screens, I started thinking about all sorts of logic that would need to be implemented for a variety of edge cases, and it made me pause. As it is, it works most of the time for many of the cases, and the dual screen setup really complicates things as the system itself doesn't always like to acknowledge the screen before the screen says hello.

It's not as easy as it looks on the face of it, I agree. I may tinker some more, but right now I'm favoring leaving it and just saying thanks for a great little utility. On Mar 20, 2023 at 5:56 PM +0000, relikd @.***>, wrote:

Played around a bit. I see no way around this issue. Actually, I am wondering why it did work in the first place ... I only get screen change events after a display was attached / detached (when it is already to late to store the window positions). Somehow it still works because the OS is too slow to update all windows and Memmon could read that state in the meantime. However, as soon as I add additional logic to distinguish between multi-monitor setups, the delay is too long and I get the already updated positions instead. This issue is even more relevant if your Macbook screen is the one that is being detached (closing the lid). The macbook lid updates are especially fast so that I cant even use the aforementioned delay. The window positions are just updated instantaneously. Unless I write a deamon which preemptively stores all positions, I dont see how to fix this. And honestly, I dont want to have a deamon running every second just to store the positions. That would burn the CPU for almost nothing. — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>

wallyfoo avatar Mar 20 '23 20:03 wallyfoo

Yep. Been there. Stored all window positions relative to the screen displaying it ... still not enough. Also, even though the low-level CGDisplayRegisterReconfigurationCallback is called before the applicationDidChangeScreenParameters notification, the processing is still not fast enough to make a difference.

But if you keep tinkering, here is a snippet you can use. You can use NSScreen.state() instead of just the screen count. That way, Memmon will remember the collection of displays as a single configuration and restore to display A or B respectively.

public extension NSDeviceDescriptionKey {
    /// Add missing `NSScreenNumber` description key.
    static let number = NSDeviceDescriptionKey(rawValue: "NSScreenNumber")
}

public extension NSScreen {
    static func state() -> String {
        var allDisplayIds = Set<CGDirectDisplayID>()
        for screen in NSScreen.screens {
            let num = screen.deviceDescription[.number] as! Number
            let displayId = CGDirectDisplayID(truncating: num)
            allDisplayIds.insert(displayId)
        }
        return allDisplayIds.sorted().map(String.init).joined(separator: ".")
    }
}

relikd avatar Mar 20 '23 20:03 relikd

Is this part of the new release?

realrolfje avatar Jul 24 '23 06:07 realrolfje

No, it is not. As I said in my last comment, every logic that is added on top will slightly decrease performance of the algorithm. That performance drop is enough to make the whole process useless. There are only a few milliseconds between getting the current window positions and the monitor change update. Currently, it is fast enough to get the positions before the monitor update occurs. But as soon as I add more logic (eg. window position relative to each monitor), the monitor update already happened.

I cant see a way to do that without periodically fetching the window positions before the monitor update triggers. This would need to happen at least every second and the majority of time unnecessarily. It would just waste CPU time.

relikd avatar Jul 24 '23 07:07 relikd