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

Freeze while clicking/moving the title bar #5656

Open
Scellow opened this issue Apr 14, 2017 · 29 comments

Comments

Projects
None yet
9 participants
@Scellow
Copy link

commented Apr 14, 2017

Hello

Currently each time you click or hold the mouse button or drag the title bar the window will freeze

I don't think that should happen, any idea ?

MonoGame version tested:

  • 3.6 DesktopGL
  • 3.5 DesktopGL

OS:

  • Windows 10
@Jjagg

This comment has been minimized.

Copy link
Contributor

commented Apr 14, 2017

That's expected behaviour. The same happens in XNA.

@Scellow

This comment has been minimized.

Copy link
Author

commented Apr 14, 2017

It should be treated as a bug imo, this is really annoying specially in networked games

@Jjagg

This comment has been minimized.

Copy link
Contributor

commented Apr 14, 2017

I agree it would be nice to not block the game. I'll play around a bit to try and fix it. Currently doing some stuff for DX, so that'll be first. @tomspilman Do you agree we should treat this as a bug?

@tomspilman

This comment has been minimized.

Copy link
Member

commented Apr 14, 2017

This sounds similar to the window resizing discussion we had before. In XNA the window updates were disabled during resize or window dragging. I think we agreed if we wanted to have the window continue to update during resize (or dragging in this case) that we want to make it something the developer opts-in for.

@Jjagg

This comment has been minimized.

Copy link
Contributor

commented Apr 14, 2017

This is different because the game logic is completely blocked in this case, so update isn't even called. The discussion in the other thread was about resizing the back buffer every frame during a window resize.

The issue here is that Application.DoEvents blocks while the user is resizing or dragging the window. We could use a timer to make sure Game.Tick is still called during these operations. I would prefer this to happen by default, but if it's opt-in that's fine too.
It would be good to at least have some way to keep the game going, because like @Scellow said this can be an issue for some types of games.

@tomspilman

This comment has been minimized.

Copy link
Member

commented Apr 15, 2017

This is different because the game logic is completely blocked in this case

You sure Update isn't also blocked in XNA on window dragging?

@Jjagg

This comment has been minimized.

Copy link
Contributor

commented Apr 15, 2017

I phrased that wrong. Yeah it is, but that's not what the other discussion was about. This is about the run loop blocking when dragging/resizing while the other discussion was about resizing the backbuffer during window resizing. There's an argument for not resizing the backbuffer every frame, but is there for blocking the run loop during window resize/move? There might be conflicts if you try to change window size in your game logic during the dragging operation, but that can be worked around. Other than that I don't see any downsides.

@cra0zy

This comment has been minimized.

Copy link
Member

commented Apr 15, 2017

On Mac/Linux the window contents does not get frozen while you drag the window.

@Jjagg

This comment has been minimized.

Copy link
Contributor

commented Apr 15, 2017

That might make it hard to get right on Windows under SDL :/
Or maybe not, since it's Win32 in the backend we could maybe just do something like

if (event is resize start && platform is windows)
{
    Start Win32 timer like in DX projects
}
if (event is resize end && platform is windows)
{
    Kill Win32 timer
}

in the event handling code. Since PInvoke entry points are dynamically found that won't throw on Mac/Linux.

@Apostolique

This comment has been minimized.

Copy link

commented Mar 24, 2018

Any news on this? It's really annoying that the game completely pauses when [clicking / holding click on title bar / dragging the window around].

Edit: Relevant post: https://gamedev.stackexchange.com/questions/51376/how-do-i-prevent-xna-from-pausing-updates-while-the-window-is-being-resized-move

@tomspilman

This comment has been minimized.

Copy link
Member

commented Mar 28, 2018

Any news on this?

I am certain it can be done. But no one has spent the time yet implementing the feature under the Windows DirectX platform.

@squarebananas

This comment has been minimized.

Copy link

commented Mar 28, 2018

Noticed this post just and was planning on having a look at this anyway this week. It seems that anything under Game.Run including the run loop is blocked while title bar is held. As far as I could tell this block seems to happen due to the form's behaviour rather than anything Monogame is overriding (unless I missed something).

I tried this just as a temporary solution and it seemed to work. However I'm not 100% confident this will cover everything and really it is just proof of concept showing it is at least possible. It can probably be achieved in a much better way.

To try it out make these changes in WinFormsGameWindow.cs

Add the following next to the existing event handlers inside the WinFormsGameWindow constructor
Form.ResizeBegin += OnResizeBegin;

Add the following at the start of the OnResizeEnd method
windowMovingUpdatesRequired = false;

Change the following inside the RunLoop method
UpdateWindows();
Game.Tick
to this
TryGameTick();

Finally place this inside the class

bool windowMovingUpdatesRequired = false;
public async void OnResizeBegin(object sender, EventArgs eventArgs)
{
    windowMovingUpdatesRequired = true;
    while (windowMovingUpdatesRequired == true)
    {
        TryGameTick();
        await System.Threading.Tasks.Task.Delay(1);
    }
}

bool gameTickAlreadyRunning = false;
public void TryGameTick()
{
    if (gameTickAlreadyRunning == false)
    {
        gameTickAlreadyRunning = true;
        UpdateWindows();
        Game.Tick();
        gameTickAlreadyRunning = false;
    }
 }

Basically this works by attempting to run Game.Tick inside a new loop after OnResizeBegin is called (which occurs when the title bar is moved). This will continue until OnResizeEnd is called and then the Game.Tick calls will continue from RunLoop instead. I'm not sure if the TryGameTick method is actually necessary but I've left it in as a precaution against starting Game.Tick again before it has ended.

One thing I have noticed is grabbing the title bar without moving the mouse at all will cause a freeze for half a second anyway. If the mouse is moved just slightly though this freeze will end early.

@Apostolique

This comment has been minimized.

Copy link

commented Mar 29, 2018

I am certain it can be done. But no one has spent the time yet implementing the feature under the Windows DirectX platform.

It also happens in Windows OpenGL.

btw good work @squarebananas

@nkast

This comment has been minimized.

Copy link
Contributor

commented Mar 30, 2018

The stackexchange link posted by @Apostolique has some more links about this, this one explains a lot about the issue: https://www.gamedev.net/forums/topic/488074-win32-message-pump-and-opengl---rendering-pauses-while-draggingresizing/?tab=comments#comment-4189300

There are only two things you can do. Run the gameloop on it's own thread, or handle move/resize messages internally, (don't pass them down to DefWindowProc() ),
In that case, I'd say that it's best to set the Game.IsActive = false during the resize/move.

@nkast

This comment has been minimized.

Copy link
Contributor

commented Mar 30, 2018

One other thing I noticed, is that if you resize the window you will see a while background filling the rest of the window. It looks bad and just makes people wonder if something is wrong.
XNA would stretch content of the window, no idea how it does that.

I tried a couple of things, setting the swapchain to Stretched or Width/Height to 0.
The content wont get refreshed until the next present().

@nkast

This comment has been minimized.

Copy link
Contributor

commented Mar 30, 2018

here:

private void OnResize(object sender, EventArgs eventArgs)
{
if (_switchingFullScreen || Form.IsResizing)
return;

I replaced it with:

            if (_switchingFullScreen || Form.IsResizing)
            {
                // repaint the window
                this.Game.GraphicsDevice.Present();
                return;
            }

@tomspilman , @Jjagg
What can go wrong with that?


We can now override OnPaintBackrground or set ControlStyles.AllPaintingInWmPaint. There no need to repaint the control below.

@cra0zy

This comment has been minimized.

Copy link
Member

commented Mar 30, 2018

I think I have a good idea on how to fix this for the SDL side.

@cra0zy

This comment has been minimized.

Copy link
Member

commented Mar 30, 2018

I thought SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP would be helpful, but nope :(

@MichaelDePiazzi

This comment has been minimized.

Copy link
Contributor

commented Mar 31, 2018

I would also love a solution to this. For networked multiplayer games like mine, this can cause some issues. I'm liking @squarebananas idea of temporarily running the game loop on another thread while the resize is occurring. It definitely seems promising.

@Apostolique

This comment has been minimized.

Copy link

commented Apr 1, 2018

@MichaelDePiazzi The solution I have in my game for multiplayer is to not use the default monogame GameTime. I use StopWatch from System.Diagnostics instead. This one doesn't get out of sync no matter what. (I was told it was a bad practice to do that, but haven't seen any proof yet.)

The Network code is running on a different thread anyway.

@Apostolique

This comment has been minimized.

Copy link

commented Apr 11, 2018

Related issue: #5590

@MichaelDePiazzi

This comment has been minimized.

Copy link
Contributor

commented Apr 12, 2018

FYI - I've tried out @squarebananas solution, and it seems to work quite well! I'll be releasing an experimental build of my game soon to test it out further.

I did tweak it slightly though and used a timer to avoid the allocations from Task.Delay. I also didn't bother with TryGameTick. It didn't seem necessary with this timer approach given everything runs on the same thread.

My version looks like this:

private void OnResizeBegin(object sender, EventArgs e)
{
    _isResizeTickEnabled = true;
    _resizeTickTimer.Enabled = true;
}

private void OnResizeTick(object sender, System.Timers.ElapsedEventArgs e)
{
    if (!_isResizeTickEnabled)
        return;
    UpdateWindows();
    Game.Tick();
    _resizeTickTimer.Enabled = true;
}

private void OnResizeEnd(object sender, EventArgs eventArgs)
{
    _isResizeTickEnabled = false;
    _resizeTickTimer.Enabled = false;
...

And the timer is initialised in the constructor as follows:

_resizeTickTimer = new System.Timers.Timer(1) { SynchronizingObject = Form, AutoReset = false };
_resizeTickTimer.Elapsed += OnResizeTick;
@Jjagg

This comment has been minimized.

Copy link
Contributor

commented Dec 10, 2018

@MichaelDePiazzi Did your changes work out?

@MichaelDePiazzi

This comment has been minimized.

Copy link
Contributor

commented Dec 11, 2018

@Jjagg Yes, it has worked quite well for me. This logic has been in the public release of my game for several months now and there doesn't seem to be any issues with it. It has also proven to be very useful for video playback as the timing for that seems to mess up if updates fall behind.

Note that update timing won't be accurate while this is engaged. But the important thing is that updates are still happening and not falling behind.

If you are good with this as a solution, then I'd be happy to submit a PR to get these changes merged in.

@Jjagg

This comment has been minimized.

Copy link
Contributor

commented Dec 11, 2018

@MichaelDePiazzi Yes, that would be great! :)

@MichaelDePiazzi

This comment has been minimized.

Copy link
Contributor

commented Dec 12, 2018

@Jjagg No problem, I'll get on to this as soon as I can.

@MichaelDePiazzi

This comment has been minimized.

Copy link
Contributor

commented Dec 14, 2018

@Jjagg Ok, I've just submitted PR #6594 which works around this issue on the Windows DirectX build.

The DesktopGL build will need a different fix though, so this issue is still not fully resolved. I'm not familiar with the DesktopGL build or SDL though, so I'm not sure how to do a similar workaround for it.

@MichaelDePiazzi

This comment has been minimized.

Copy link
Contributor

commented Dec 17, 2018

@Jjagg This issue should get the "OpenGL" label added. And the "DirectX" one can probably be removed since that's resolved now.

@Jjagg Jjagg added OpenGL and removed DirectX labels Dec 17, 2018

@briermay

This comment has been minimized.

Copy link

commented May 2, 2019

is there still no fix for this ? I'm using windows 10 and MonoGame 3.7 and Cross platform desktop project upon start locks up still. and as for someone saying XNA had the same behavior, no it does not I have XNA on my laptop for building content (i really dislike the way MonoGame does it) and it does not exhibit the same behavior (although its Direct X not OpenGL)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.