Running a Mini under macOS Sonoma 14.6.1, with two screens. I move my app’s main window to the second screen, and make it fit in there nicely, and quit it. It saves its position (x, y, height, width), which should be restored when I open it again. But it sits jammed up against the left edge of the main screen.
So I added a Moved event, which fires twice during startup, once to set Left to the correct (saved) value (which would put it on the second screen), and a second time to set it to 4. Next I raise a runtime exception which fires on the second Moved event, showing this in the Stack:
(the stack output has been tidied up with @Beatrix_Willius 's excellent stack cleaner method).
Am I right in thinking that this just indicates that neither the app nor the user (me) moved the window - in which case it must be the OS? Or am I missing something?
You should be able to see what is causing your moved event. I put an f.delete into the moved event for a nil folderitem and got the following result:
Sub MaxModel.Notify(string)
Sub NotificationCenter.Post(string, string)
Sub NotificationManager.Post(string)
Sub ErrorException.Constructor(RuntimeException, string)
Sub MainWindow.MainWindow.Event_Moved(MainWindow.MainWindow)
Function NSWindowMBS.setFrameUsingName(string, boolean) as boolean
Sub LoadWindowPosition.Constructor(Window, string)
Sub MainWindow.MainWindow.Event_Open(MainWindow.MainWindow)
Sub Window.Constructor()
Sub DBWindow.Constructor(MainWindowController)
Sub App.Event_Open()
Sub Application._CallFunctionWithExceptionHandling()
I use window.open to load the load the window position. There is also a boolean OpenDone so that setting the window position doesn’t save it again. The moved event of the main window:
if not OpenDone then Return
dim theSaver as new SaveWindowPosition(self, self.TrueWindow.getWindowName)
#Pragma Unused theSaver
All the initialisation for the app (well, most of it) is done in the app’s Opening event. Probably more than should be being done there, but at the time I was converting this app to Xojo from a mixture of PHP and javascript, I was much less well versed in the concept of having controls do their own initialisation.
Having scanned through various sets of Xojo search results I can’t find any other place where I am setting the window position in code.
I only added the Moved event as a debugging asset - normally it does not exist in the app. The position save for the window is done when the app quits.
Edit: I should also add that, I’m only triggering an exception in the Moved event so that the app will save the Stack for rme as it crashes. And it’s only doing that when window.left gets set to less than 10.
It seems that after all initialisation is complete (including setting the window bounds to saved values), something gets triggered to move the window 2560 px leftwards, if .Left is then greater than 2560. This just happens to be the exact width of the DisplayAt(0).
I may have a workaround, however. I tried using Timer.CallLater to set the bounds after some delay, and provided the delay is 600msec or so, or more, then moving the window to its saved position sticks. This is, of course, a hack.
Edit: but the window has to have .Visible = True for even this hack to work.
If I try this, it refuses to relocate the window to the second screen no matter how long the delay. It only relocates after the timer expires provided the window is visible while the timer is running.
I’m having to do everything (that is, almost all initialisation) in the app’s Opening event, because that is the only way I can guarantee that app variables are properly initialised and databases exist before I try to use them.
(Heavily whispered aside: too bad Xojo doesn’t have a main() function that runs first when the app starts, before anything else at all, where I could put all this startup code).
The code to set the bounds after a delay is:
timer.CallLater (1000, AddressOf moveMain, new Rect (framex, framey, winWidth, winHeight))
.
and moveMain consists of:
Sub moveMain (b as Variant)
MainWindow.Bounds = Rect(b)
End Sub
This is under macOS with each screen having its own set of Spaces.
That would be one of the first things to turn off, should I be moving to that OS. I also need to find out how to disable it under Win-11. That would make the one day a week where I have to use Windows, rather less irritating.
Sure. But to know where the user left the window, I have to read its saved coordinates from an SQLite database. My SQLite wrappers handle errors and report into the Logfile - which must therefore exist at the time. Circular problem.
Don’t try and position windows in the App open event. Do it in the Window’s open event. Otherwise the window initialisation can position the window after you do.