Restoring window location - Mac, Windows, Linux

Hi all,

My app, which needs to run on Mac, Windows, Linux needs to remember and restore the location of various windows and it should restore the display the window was on if possible if the user has multiple displays.

This last item, display or screen, is the question. I have not found how to set that when creating a new window. I had hoped that just setting the top and left would do it however depending upon the screen configuration I’ve seen these values go negative and I’m not sure what the means but restoring the negative position puts the window offscreen somewhere.

I’ve searched the forums and Google and found people referring to using an NSScreen object which seems to be a Mac reference but there were no code examples of how to use this and the solution I need, needs to work across all three OSes.

I found a small function in the forum here that at least on Mac seems to return which display the window is on:

dim sc As Integer = ScreenCount
for i as integer = 0 to sc-1 
  if x >= Screen(i).left and x <= screen(i).width + Screen(i).left and y >= screen(i).top and y <= screen(i).height + screen(i).top then 
    return i 
  end if 
next 
return 0

This seems, at least on my Mac, to return different screen numbers. But again how do I reopen the window on that screen?

Thanks in advance!

Maybe @Sam_Rowlands Code can help here?

Thank you sir! Giving it a go…

This is possible: I’ve done that: coded on MacOS, running on Windows XP at first, then WIndows 10 and now WIndows 11.

At quit time, the current window position on the Monitor is saved into a preference (text) file, loaded and applied at run time.

Works like a charm; I loved that feature !

The main (default) screen’s left and top will always be 0.
If you have another screen at the right of the main screen, its left will be equal to the main screen’s width (like if the two screens were contiguous). Same for a screen below the main screen (its top will be equal to the height of the main screen).

Then, as you’d expect, if you have another screen at the left of the main screen, its left will be 0-its width (it’s just a matter of geometry; the reference point being obviously 0 (i.e. the main screen), that extra screen on the left side is at 0-its width). Same for top, with a screen above the main one.

So if you had 3 screens, with 1920 of width for each and the main one is the rightmost one, the right screen’s left=0, the middle screen’s left=-1920 and the leftmost screen’s left=-3840.
Nothing special.

Doesn’t sound right. Do you keep the same screens arrangement between saving and restoring?
What if you try to move a window in a blank project, with the values you expect? (to rule out other parts of code that may interfere)

On Linux or WIndows: certainly.

But it will be news for me if this happens with macOS…

I will report back here what I learn/find.

I am testing the code provided in the first reply to see if it helps.

I have tested the position code I have in a small project and see the same results that at times the values become negative for top, left when the window was on a screen that is no longer connected.

Still trying to debug how that happens.

With respect to next monitor being relative to main screen 0, 0 + size, I think that it depends, but I could be wrong, on if your main monitor is left or right in your arrangement. I’m going to test if this is the case.

When I first saw the negative top/left I had my mac with main screen on the right of my big monitor and arranged them in the OS control panel so the big monitor was on the left. I believe this resulted in window coordinates on my window on the big screen to be negative (relative to main screen 0). I could be wrong so don’t shoot me yet. Still testing that theory.

Thanks for all the replies guys! I’ll report back what I find.

If you save the window top and left upon window closure, it will reappear on the same screen.

I do that in my apps; I add these values to a dictionary, and save the content of the dictionary into a subfolder of ApplicationData.

Upon launch of the app I load the content of the dictionary, so I can reinstate the windows top and left when I open them.

Hi Michel,

So that I understand and I do. But what is not working well is if I position a window on a big screen, not on my mac “main screen”. Close the app which saves the window position. Disconnect the big monitor and re-open the app, the window is offscreen because my code is forcing it to those coordinates.

This is part of the issue I want to solve.

You’ll need to loop through the available screens and check whether the saved coordinates fall within any of them. If not, maybe default to the main screen. Most of us don’t change the configuration of our monitors, so it’s not an issue.

I ended up deciding to just store the current window configuration (array of monitors and size / offsets) with my last saved app window positions. Then on start up, first check if the configuration has changed and only then restore the last window position if the configuration has not changed. If it has changed, I allow the default position set in the window’s properties to take effect.

For me personally, the most common case of a configuration change is when my laptop is not docked in my office. While docked, I use a higher resolution because I have more screen real estate available.

I switch between my MacBook built in monitor and a 27" attached monitor, so if a have a window at the bottom of the larger monitor and later restart the app on the smaller one, it may be partly out of the viewport. I don’t really see this as unexpected or a problem.

I would clip Top and Left to zero so they can’t be restored as negative values such that you can’t reach the title bar with the mouse – but other than that, at least for my purposes, it’s been fine to save top, left, width and height on exit.

Sometimes the OS’s don’t know that a screen isn’t there anymore. I had to implement a “Collect Windows” method to move all windows to the main screen.

Yes, I know, but at the time I answered, the OP didn’t stated he removed screens between runs. Therefore, I assumed he got a weird behaviour with two consecutive runs :wink:.

And you chose one way among the many available. Is there even a unified expected way between every OS? It’s time to check HIG again…

My assumption is that one should check for every restored window if the expected screen still exists. If yes, restore it, if not, do nothing (use system default).

So when the user has 3 (or more) screens and puts all windows among screens 1&2, then later removes the third screen, your app won’t use the valid screens 1&2.

When you restart your app, you have to programmatically move the windows to the smallest screen when the other is no longer there. That’s the decision we’re talking about here.

You can use Screen.AvailableLeft (top, width, height) to know whether your window is in a valid location.

1 Like

True, but at least they are visible. Anybody using multiple monitors should already have shortcut keys to quickly move windows to another monitor or other size/placement. I define several shortcut keys for just that purpose in BetterTouchTool.

When I only hook up one of my external 4k 15.6" monitors to my 16" MBP instead of two of them when not docked in my office, I use the layout different than when in a single screen or dual screen arrangement. So even if I did what you point out, I’d be likely to move them again anyway.

@Douglas, this is what I think makes the most sense. I can pretty easily use that screen loop code I found to store the available screen bounds then when restoring a window, like you say, check if those window bounds are valid. If not move it to a screen that it.

This is great idea and I think the right way to solve this problem. Hopefully it works as well in Windows and Linux.

Thanks - Mark

For many years, I’ve been saving windows coordinates and then restoring them and it’s worked fine - until this week, when a user complained that windows on a second monitor weren’t re-opening there. I’m saving the window coordinates and then restoring them when opening another instance of that window type, so I was baffled as to why it wouldn’t work when the second monitor hadn’t moved.

What I’ve found is that if the stored coordinates include negative numbers (such as Window.Top on a window that is above the primary screen (for example, when my code does a mywindow.top = -1146), it becomes a positive number just below the primary screen’s menu bar. Dragging the window up to the second monitor and looking at its properties, the .top coordinate is correctly negative.

I’m running Xojo 2022 R3 build 58045, did something change? I’ve also tried locating the new window instance using the Center property, with the same problem.

Thoughts?

I don’t suppose you are using format to store your numbers, If you forget the - at the start of the format string negative numbers come out as positive. Which has bitten be a few times.

String = format( number, "0" ) ' is always positive
String = format( number, "-0" ) ' can be positive or negative

No, everything is stored as integers, and I can see the values are negative in the debugger. It’s only when they’re assigned to the window coordinates that they turn into positive numbers. And it happens when I assign the values to either window bounds or top/left/height/width properties.

This is the wrong Forum to talk about it, but yes.