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

Base window size and position is not remembered #12006

Closed
flowCRANE opened this issue Jan 17, 2025 · 23 comments · Fixed by #12011 or #12030
Closed

Base window size and position is not remembered #12006

flowCRANE opened this issue Jan 17, 2025 · 23 comments · Fixed by #12011 or #12030
Assignees
Milestone

Comments

@flowCRANE
Copy link

flowCRANE commented Jan 17, 2025

Windows 10, SDL 3.1.10

The full description of the issue can be found in the thread Base window size and position is not remembered with lists of steps to reproduce issues, below are direct links for easier navigation. In this thread I have added an attachment for each of the three tests and the attachments contain the source code of the testers (Free Pascal, sources are also provided in the posts) and compiled exe's to test without having to compile anything.

Window with standard decoration:

  • The first test showing that SDL does not remember the base window size and position when entering fullscreen while the window is maximized.

Borderless window with custom decoration and hit-test:

  • The second test showing that SDL cannot correctly restore a window from a minimized form if a maximized window was minimized.
  • The third test showing that SDL does not remember the base window size and position when entering fullscreen while the window is maximized.

In short, there are two problems. Only the size and position of the window before the window style change are remembered, so if you maximize the window and then go fullscreen, the size of the window before maximization is lost. So when you exit fullscreen, the window is restored to its maximized form, but it is not possible to restore a window from maximized to windowed form. This is true for both standard decorated and borderless windows.

The second problem only affects borderless windows that have their own hit-test callback. If you maximize and then minimize such a window, after restoring it from the taskbar the window takes on a completely incorrect size and position. SDL does not restore a maximized borderless window to its maximized form (its form before minimization).

@slouken slouken added this to the 3.2.0 milestone Jan 17, 2025
@slouken
Copy link
Collaborator

slouken commented Jan 17, 2025

@Kontrabant, is this something you can look into?

@Kontrabant
Copy link
Contributor

Kontrabant commented Jan 17, 2025

I tried your examples on both Win 10 and Win 11 (latest updates in both cases), and they behave correctly for me, as does performing the same sequence of operations with testsprite in the SDL test suite, as well as the automated tests, which tests the maximize->enter fullscreen->leave fullscreen->restore pattern as well.

On all platforms, SDL defers managing the window size and position to the desktop wherever possible, unless an explicit change was requested. In this case, when leaving the maximized state, SDL just removes the maximized style, and it's up to Windows to put the window back to the previous size/position.

@Kontrabant
Copy link
Contributor

I think we hit a bug like this before (#9338), and it was related to Windows not restoring the proper size when leaving the maximized state.

@Kontrabant
Copy link
Contributor

@flowCRANE if you run testsprite --resizable --noframe and do the following:

  • ctrl+m to maximize
  • alt+enter to enter fullscreen
  • alt+enter to leave fullscreen
  • ctrl+m to restore

does it restore properly? Problems like this are much easier to debug when they can be replicated via the test suite.

@flowCRANE
Copy link
Author

flowCRANE commented Jan 17, 2025

Please, send me the compiled test and I'll check it out. I don't work with C and I don't have the tools for it right now, so I won't compile these tests for now. But I promise that in the near future, when I finally deal with the problems with handling window modes, I'll take care of this topic so that I can compile the sources myself and test them. :)

I'm guessing the problem is that I have two monitors (extended desktop) and the secondary monitor is to the left of the primary monitor, causing it to have a negative X coordinate (i.e. -1280.0). Because of this monitor arrangement, even though it is completely correct, I constantly find bugs in various programs, including for example the Lazarus IDE, because it also does not handle this for some functions (like the popup of the designer window). Complete mess.

@Kontrabant
Copy link
Contributor

I'm guessing the problem is that I have two monitors (extended desktop) and the secondary monitor is to the left of the primary monitor, causing it to have a negative X coordinate (i.e. -1280.0). Because of this monitor arrangement, even though it is completely correct, I constantly find bugs in various programs, including for example the Lazarus IDE, because it also does not handle this for some functions (like the popup of the designer window). Complete mess.

Just to be sure, I tried this display configuration as well, and, unfortunately, I still can't replicate your issue. Your supplied reproduction cases work correctly on my system, even on a dual-display setup with one display having negative coordinates.

@flowCRANE
Copy link
Author

Damn. As usual the problem only occurs with me... I can reproduce this problem 100% of the time myself, both in my test program (the code for which I provided in the linked thread) and in my actual game project that I'm working on.

And did you check how your tester behaves when the taskbar is pinned to the top of the screen (on both screens), like mine is? Maybe that's the reason why Windows can't handle maximization correctly.

@Kontrabant
Copy link
Contributor

Yes, Win 10 still works correctly, and Win 11 is moot as it doesn't allow moving the taskbar to the top anymore.

@flowCRANE
Copy link
Author

flowCRANE commented Jan 17, 2025

I've changed the taskbar location to the Bottom and there is no difference — still there is a problem. I maximize the borderless window, minimize it, and when I click the application button on the taskbar to restore the window, the effect is as follows:

Image

The window is moved to the -1280,0 location (who knows why) and its size is huge. When I press Alt+Space to show the system popup menu in the top left corner of the window, I see this:

Image

The window is completely messed up — its top left corner is on the second monitor. :(

And if I click the Resotre item in this system popup menu, the window actually restores the correct size and position:

Image

@Kontrabant
Copy link
Contributor

Kontrabant commented Jan 17, 2025

Ok, I can reproduce this now. The problem is that borderless windows need their size corrected to avoid spilling over the side of the desktop due to Windows quirkiness, so the display for the window is queried and the desktop dimensions from it are used to calculate the client area. If the window is being restored from minimized, the monitor returned by MonitorFromWindow can be incorrect (null, or the 'nearest', which in this case is the display to the left since the window size spills over slightly), so we'll need to fallback to retrieving the monitor from the last known window position in this case.

@flowCRANE
Copy link
Author

flowCRANE commented Jan 17, 2025

Ok, so there is hope that this problem will be fixed. Great!

In theory I could fix this, just like I fixed the problem with fullscreen support. The problem is that the SDL_EVENT_WINDOW_RESTORED event is sent both after restoring the window from the maximized state and from the minimized state. To do a workaround, I would have to remember whether the window was minimized or not, and this only complicates the implementation. If SDL doesn't help me fix the problem of minimizing a borderless maximized window, I will have no choice but to implement such dirty hacks.

It would be much easier if there were separate events for these two cases. Then the application would know whether the window was restored from the minimized or maximized state. But that's just a loose thought.

@Kontrabant
Copy link
Contributor

The minimization issue is fixed. Still not sure about why the base size is being lost, though.

@flowCRANE
Copy link
Author

flowCRANE commented Jan 18, 2025

What about the second problem, i.e. exiting fullscreen and returning to maximized form? Have you checked it out?

@Kontrabant
Copy link
Contributor

I still can't reproduce that behavior on my end.

@flowCRANE
Copy link
Author

flowCRANE commented Jan 19, 2025

@flowCRANE if you run testsprite --resizable --noframe and do the following:

  • ctrl+m to maximize
  • alt+enter to enter fullscreen
  • alt+enter to leave fullscreen
  • ctrl+m to restore

does it restore properly?

I checked this test and no, it does not restore properly. There is exactly the same problem as in my main project, that is, exiting fullscreen mode to maximized form and then restoring the window causes the window size to be set to match the maximized window size, instead of into a small window form.

@flowCRANE
Copy link
Author

flowCRANE commented Jan 19, 2025

I have already installed Visual Studio and cloned the SDL repository, so I am testing the latest sources and also checking how SDL works for my main project.

For now, I can confirm that three issues have been resolved:

  1. Hit-test callback allows to stretch borderless window without problems (thanks to adding WS_THICKFRAME style).
  2. SDL generates mouse events for areas for which hit-test callback returns SDL_HITTEST_DRAGGABLE, so I can show system popup menu for custom title bar without problems, after clicking RMB (with SDL_ShowWindowSystemMenu function).
  3. Minimizing maximized window and restoring it from taskbar no longer causes problems with setting wrong window size — restoring from minimized form works correctly.

There is only one problem left, which is the following list of steps:

  1. Show a small borderless resizable window,
  2. Maximize it,
  3. Enable fullscreen,
  4. Disable fullscreen,
  5. Restore the window.

The window size will not be restored to the size appropriate for point 1. In my case, the window size is set to such a size that the OS detects it as a fullscreen window and enables desktop fullscreen on its own. I replicate this 100% of the time, both for testsprite --resizable --noframe and in my test program, the sources of which I provided in the linked forum topic.

@Kontrabant
Copy link
Contributor

Kontrabant commented Jan 19, 2025

This sounds like Windows is keeping the fullscreen size as the base size, because when leaving fullscreen, we restore the maximized state, and rely on Windows to put the window back as it should be when de-maximized. What we could try is having the window first resize to the floating base size, then re-enter maximized if necessary, but that may cause some visual ugliness as the window changes states multiple times. I'll set this up for you to try.

Just out of curiosity, is your version of Win10 completely updated? This issue did appear in the past (again, #9338), and it seemed to start after a Windows update, and disappeared on its own after a later Windows update.

@flowCRANE
Copy link
Author

flowCRANE commented Jan 19, 2025

Yes, it is updated to the latest version — something I never neglect.


You know, these problems didn't bother me before, and I didn't even know about some of them because I didn't use borderless windows. Now that I have implemented borderless windows in my project, I have discovered a problem with minimizing a maximized window, but this has been fixed.

The remaining problem (with maximization and fullscreen) does not concern my project, because in it I support fullscreen in such a way that the engine takes care of correctly restoring the window size (I also did this in previous projects). However, this bug exists, so it would be good to fix it for the sake of other SDL users.

@slouken
Copy link
Collaborator

slouken commented Jan 19, 2025

Okay, thanks for the feedback. I'll leave the bug open, but if it's not blocking you I'll bump it out of the shipping milestone.

@slouken slouken modified the milestones: 3.2.0, 3.x Jan 19, 2025
@flowCRANE
Copy link
Author

Yeah, it's not blocking me, so go ahead.

@Kontrabant
Copy link
Contributor

If you have a moment, could you try this branch: https://github.com/Kontrabant/SDL/tree/win32_monitor_fix

I still can't replicate the issue of the window not being restored to the proper size on any of my setups, but I suspect I know what is happening, and this should, hopefully, fix it.

In particular, this was a helpful hint:

In my case, the window size is set to such a size that the OS detects it as a fullscreen window and enables desktop fullscreen on its own.

What is probably happening is that, when entering fullscreen, the window is resized to cover the screen, and since the maximized style is unset before doing this, the base size is being overwritten, resulting in the window going back to the fullscreen size when leaving maximized. This branch changes the behavior to always set the window back to the old base size before re-maximizing it when leaving fullscreen.

@flowCRANE
Copy link
Author

flowCRANE commented Jan 20, 2025

Yeah, SDL library compiled from win32_monitor_fix branch works correctly and solves the problem with restoring maximized window after disabling fullscreen. I've tested the testsprite --resizable --noframe and also my test project, and I can confirm that everything works fine, in both cases.

Thanks for dealing with this topic. :)

@Kontrabant
Copy link
Contributor

Kontrabant commented Jan 20, 2025

Great, thanks for testing this on your end!

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