Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does not restore windows after sleep mode. #11

Open
realrolfje opened this issue Jan 25, 2023 · 18 comments
Open

Does not restore windows after sleep mode. #11

realrolfje opened this issue Jan 25, 2023 · 18 comments

Comments

@realrolfje
Copy link

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!

@relikd
Copy link
Owner

relikd commented Jan 25, 2023

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?

@realrolfje
Copy link
Author

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.

@relikd
Copy link
Owner

relikd commented Jan 25, 2023

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 👍

@MrFussyfont
Copy link

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

@relikd
Copy link
Owner

relikd commented Feb 1, 2023

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

@wallyfoo
Copy link

wallyfoo commented Feb 9, 2023

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.

@relikd
Copy link
Owner

relikd commented Feb 20, 2023

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?

@MrFussyfont
Copy link

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).

@relikd
Copy link
Owner

relikd commented Feb 21, 2023

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.

@wallyfoo
Copy link

wallyfoo commented Feb 21, 2023

@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...?

@realrolfje
Copy link
Author

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.

@MrFussyfont
Copy link

@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

@relikd
Copy link
Owner

relikd commented Mar 13, 2023

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
Copy link
Owner

relikd commented Mar 20, 2023

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.

@wallyfoo
Copy link

wallyfoo commented Mar 20, 2023 via email

@relikd
Copy link
Owner

relikd commented Mar 20, 2023

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: ".")
    }
}

@realrolfje
Copy link
Author

Is this part of the new release?

@relikd
Copy link
Owner

relikd commented Jul 24, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants