From bc6d7ad5a358c7827aab7275adba72a58532ed2d Mon Sep 17 00:00:00 2001 From: codereader Date: Sun, 12 Jul 2020 14:44:39 +0200 Subject: [PATCH] #5231: Implement the shutdown handler, to ask for saving any pending changes to the map. Fix crash at shutdown if the progress dialog is not cleaned up before the module it has been instantiated from is unloaded. --- radiant/ui/mainframe/ScreenUpdateBlocker.cpp | 4 ++++ radiantcore/map/Map.cpp | 22 +++++++++++++++++--- radiantcore/map/Map.h | 19 ++++++++++------- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/radiant/ui/mainframe/ScreenUpdateBlocker.cpp b/radiant/ui/mainframe/ScreenUpdateBlocker.cpp index baf12f7461..505ec1ac7f 100644 --- a/radiant/ui/mainframe/ScreenUpdateBlocker.cpp +++ b/radiant/ui/mainframe/ScreenUpdateBlocker.cpp @@ -63,6 +63,10 @@ ScreenUpdateBlocker::~ScreenUpdateBlocker() // Re-draw the scene to clear any artefacts in the buffer GlobalMainFrame().updateAllWindows(); + + // Run one idle event loop, to allow wxWidgets to clean up the + // modal progress dialog window + wxTheApp->ProcessIdle(); } void ScreenUpdateBlocker::pulse() diff --git a/radiantcore/map/Map.cpp b/radiantcore/map/Map.cpp index 03bb9853f9..50bb90ae97 100644 --- a/radiantcore/map/Map.cpp +++ b/radiantcore/map/Map.cpp @@ -65,7 +65,8 @@ namespace Map::Map() : _lastCopyMapName(""), - _saveInProgress(false) + _saveInProgress(false), + _shutdownListener(0) { _mapSaveTimer.Pause(); } @@ -492,13 +493,13 @@ bool Map::askForSave(const std::string& title) } // Ask the user - ui::IDialogPtr msgBox = GlobalDialogManager().createMessageBox( + auto msgBox = GlobalDialogManager().createMessageBox( title, getSaveConfirmationText(), ui::IDialog::MESSAGE_SAVECONFIRMATION ); - ui::IDialog::Result result = msgBox->run(); + auto result = msgBox->run(); if (result == ui::IDialog::RESULT_CANCELLED) { @@ -872,10 +873,17 @@ void Map::initialiseModule(const ApplicationContext& ctx) GlobalRadiant().signal_radiantShutdown().connect( sigc::mem_fun(this, &Map::onRadiantShutdown) ); + + _shutdownListener = GlobalRadiantCore().getMessageBus().addListener( + radiant::IMessage::Type::ApplicationShutdownRequest, + radiant::TypeListener( + sigc::mem_fun(this, &Map::handleShutdownRequest))); } void Map::shutdownModule() { + GlobalRadiantCore().getMessageBus().removeListener(_shutdownListener); + _scaledModelExporter.shutdown(); GlobalSceneGraph().removeSceneObserver(this); @@ -884,6 +892,14 @@ void Map::shutdownModule() _mapPositionManager.reset(); } +void Map::handleShutdownRequest(radiant::ApplicationShutdownRequest& request) +{ + if (!askForSave(_("Exit DarkRadiant"))) + { + request.deny(); + } +} + void Map::onRadiantShutdown() { freeMap(); diff --git a/radiantcore/map/Map.h b/radiantcore/map/Map.h index 9c23e33b92..787294e961 100644 --- a/radiantcore/map/Map.h +++ b/radiantcore/map/Map.h @@ -13,6 +13,7 @@ #include "model/export/ScaledModelExporter.h" #include "model/export/ModelScalePreserver.h" #include "MapPositionManager.h" +#include "messages/ApplicationShutdownRequest.h" #include #include @@ -55,6 +56,8 @@ class Map : MapEventSignal _mapEvent; + std::size_t _shutdownListener; + private: std::string getSaveConfirmationText() const; @@ -165,13 +168,6 @@ class Map : */ MapFormatPtr getFormat(); - /** greebo: Asks the user if the current changes should be saved. - * - * @returns: true, if the user gave clearance (map was saved, had no - * changes to be saved, etc.), false, if the user hit "cancel". - */ - bool askForSave(const std::string& title); - /** greebo: Focus the XYViews and the Camera to the given point/angle. */ static void focusViews(const Vector3& point, const Vector3& angles); @@ -199,6 +195,15 @@ class Map : static void saveSelectedAsPrefab(const cmd::ArgumentList& args); private: + /** + * greebo: Asks the user if the current changes should be saved. + * + * @returns: true, if the user gave clearance (map was saved, had no + * changes to be saved, etc.), false, if the user hit "cancel". + */ + bool askForSave(const std::string& title); + + void handleShutdownRequest(radiant::ApplicationShutdownRequest& request); /** greebo: Loads a prefab and translates it to the given target coordinates */