-------- Context: --------
I’d like to dynamically resize the client window / backbuffer as the user resizes the window.
I am doing so by hooking into these events:
Form gameForm = (Form)Form.FromHandle(game.Window.Handle);
gameForm.ResizeBegin += GameForm_ResizeBegin;
gameForm.Resize += GameForm_Resize;
gameForm.ResizeEnd += GameForm_ResizeEnd;
I grab the client window size like so:
private void GameForm_Resize(object sender, EventArgs e)
{
Form gameForm = (Form)sender;
System.Drawing.Size newSize = gameForm.ClientSize;
... update GraphicsDeviceManager ...
... call ApplyChanges() ...
}
-------- Problem: --------
However, MonoGame has window centering logic for initialization, that kicks in for:
- initialization (the window is centered on the screen at launch),
- but also kicks in when it shouldn’t: on the 1st (but not subsequent) user resizing.
This causes whatever corner/edge the user is moving, to move as it should – but the enforced window centering readjusts it (which then causes a second move, since the mouse drags the corner that was just moved back to the mouse!) – which interestingly enough makes the opposite edge also resize (much like MacOS). Kind of cool – perhaps even desired, but it is inconsistent (it only does so on the 1st resize, and never again).
-------- Root Cause: --------
WinFormsGameWindow.cs
:
Has a Boolean to indicate if we moved the window:
// true if window position was moved either through code
// or by dragging/resizing the form
private bool _wasMoved;
This is set false
so that on launch, the window is forcibly resized inside of
internal void ChangeClientSize(Size clientBounds)
and ignored otherwise (it lets the user resize the window). (It’s perhaps a little odd that ChangeClientSize
has the power to reject a user sizing, just so it can handle the launch positioning, but I follow the logic.)
The problem is in the following function, which rejects the WM_SIZING / Form.IsResizing
handling, and does not allow _wasMoved
to be reset. Only after resizing is done, is it reset – “OK, launch complete, no need to forcibly center the window; allow the user to resize now.”
private void OnResize(object sender, EventArgs eventArgs)`
{
if (_switchingFullScreen || Form.IsResizing) // <<<<<<<< SHORT CIRCUIT
return;
// this event can be triggered when moving the window through Windows hotkeys
// in that case we should no longer center the window after resize
if (_lastFormState == Form.WindowState)
_wasMoved = true; // <<<<<<<<<<<<< NOT SET DURING 1ST WM_SIZING
...
-------- Solution: --------
If OnResize
didn’t short circuit on Form.IsResizing
, I think this would not only solve this problem, but it would likely allow dynamic resizing by default.