From fb542d8c7e02bd7224611941d92fcbf242ae4d28 Mon Sep 17 00:00:00 2001 From: codereader Date: Sun, 28 Jun 2020 09:48:11 +0200 Subject: [PATCH] #5231: Fix ScreenUpdateBlocker not being able to block window draw events before the main loop kicks in. --- radiant/ui/mainframe/ScreenUpdateBlocker.cpp | 63 ++++++++++++++------ radiant/ui/mainframe/ScreenUpdateBlocker.h | 9 ++- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/radiant/ui/mainframe/ScreenUpdateBlocker.cpp b/radiant/ui/mainframe/ScreenUpdateBlocker.cpp index a82b14a0a3..baf12f7461 100644 --- a/radiant/ui/mainframe/ScreenUpdateBlocker.cpp +++ b/radiant/ui/mainframe/ScreenUpdateBlocker.cpp @@ -8,8 +8,9 @@ namespace ui { ScreenUpdateBlocker::ScreenUpdateBlocker(const std::string& title, const std::string& message, bool forceDisplay) : - wxutil::ModalProgressDialog(title, GlobalMainFrame().getWxTopLevelWindow()), - _pulseAllowed(true) + _dialog(nullptr), + _pulseAllowed(true), + _title(title) { // Set the "screen updates disabled" flag (also disables autosaver) GlobalMainFrame().disableScreenUpdates(); @@ -17,11 +18,7 @@ ScreenUpdateBlocker::ScreenUpdateBlocker(const std::string& title, const std::st // Connect the realize signal to remove the window decorations if (GlobalMainFrame().isActiveApp() || forceDisplay) { - // Show this window immediately - Show(); - - // Eat all window events - _disabler.reset(new wxWindowDisabler(this)); + showModalProgressDialog(); } // Process pending events to fully show the dialog @@ -30,9 +27,20 @@ ScreenUpdateBlocker::ScreenUpdateBlocker(const std::string& title, const std::st // Register for the "is-active" changed event, to display this dialog // as soon as Radiant is getting the focus again GlobalMainFrame().getWxTopLevelWindow()->Bind(wxEVT_SET_FOCUS, &ScreenUpdateBlocker::onMainWindowFocus, this); +} + +void ScreenUpdateBlocker::showModalProgressDialog() +{ + _dialog = new wxutil::ModalProgressDialog(_title, GlobalMainFrame().getWxTopLevelWindow()); - Bind(wxEVT_CLOSE_WINDOW, &ScreenUpdateBlocker::onCloseEvent, this); - Bind(wxEVT_IDLE, [&](wxIdleEvent&) { pulse(); }); + _dialog->Bind(wxEVT_CLOSE_WINDOW, &ScreenUpdateBlocker::onCloseEvent, this); + _dialog->Bind(wxEVT_IDLE, [&](wxIdleEvent&) { pulse(); }); + + // Show this window immediately + _dialog->Show(); + + // Eat all window events + _disabler.reset(new wxWindowDisabler(_dialog)); } ScreenUpdateBlocker::~ScreenUpdateBlocker() @@ -42,6 +50,11 @@ ScreenUpdateBlocker::~ScreenUpdateBlocker() // Process pending events to flush keystroke buffer etc. wxTheApp->Yield(true); + if (_dialog != nullptr) + { + _dialog->Destroy(); + } + // Remove the event blocker, if appropriate _disabler.reset(); @@ -54,15 +67,18 @@ ScreenUpdateBlocker::~ScreenUpdateBlocker() void ScreenUpdateBlocker::pulse() { - if (_pulseAllowed) + if (_pulseAllowed && _dialog != nullptr) { - ModalProgressDialog::Pulse(); + _dialog->Pulse(); } } void ScreenUpdateBlocker::doSetProgress(float progress) { - ModalProgressDialog::setFraction(progress); + if (_dialog != nullptr) + { + _dialog->setFraction(progress); + } _pulseAllowed = false; } @@ -74,29 +90,38 @@ void ScreenUpdateBlocker::setProgress(float progress) void ScreenUpdateBlocker::doSetMessage(const std::string& message) { - ModalProgressDialog::setText(message); + if (_dialog != nullptr) + { + _dialog->setText(message); + } } void ScreenUpdateBlocker::setMessage(const std::string& message) { doSetMessage(message); - Refresh(); - Update(); + if (_dialog != nullptr) + { + _dialog->Refresh(); + _dialog->Update(); + } } void ScreenUpdateBlocker::setMessageAndProgress(const std::string& message, float progress) { - ModalProgressDialog::setTextAndFraction(message, progress); + if (_dialog != nullptr) + { + _dialog->setTextAndFraction(message, progress); + } } void ScreenUpdateBlocker::onMainWindowFocus(wxFocusEvent& ev) { // The Radiant main window has changed its active state, let's see if it became active - // and if yes, show this blocker dialog. - if (GlobalMainFrame().getWxTopLevelWindow()->IsActive() && !IsShownOnScreen()) + // and if yes, show the blocker dialog. + if (GlobalMainFrame().getWxTopLevelWindow()->IsActive() && _dialog == nullptr) { - Show(); + showModalProgressDialog(); } } diff --git a/radiant/ui/mainframe/ScreenUpdateBlocker.h b/radiant/ui/mainframe/ScreenUpdateBlocker.h index 5deb565a8e..9275cfcb68 100644 --- a/radiant/ui/mainframe/ScreenUpdateBlocker.h +++ b/radiant/ui/mainframe/ScreenUpdateBlocker.h @@ -9,15 +9,18 @@ namespace ui { class ScreenUpdateBlocker : - public IScopedScreenUpdateBlocker, - public wxutil::ModalProgressDialog + public IScopedScreenUpdateBlocker { private: + wxutil::ModalProgressDialog* _dialog; + std::unique_ptr _disabler; // Once we received a call to setProgress() further calls to pulse() are forbidden bool _pulseAllowed; + std::string _title; + public: // Pass the window title and the text message to the constructor ScreenUpdateBlocker(const std::string& title, const std::string& message, bool forceDisplay = false); @@ -36,6 +39,8 @@ class ScreenUpdateBlocker : // Called whenever the main window is changing its "active" state property. void onMainWindowFocus(wxFocusEvent& ev); void onCloseEvent(wxCloseEvent& ev); + + void showModalProgressDialog(); }; } // namespace ui