Преглед изворни кода

Reduced usage of topWindow() method

Ivan Savenko пре 2 година
родитељ
комит
ad3e54e6c0

+ 14 - 19
client/CPlayerInterface.cpp

@@ -178,7 +178,7 @@ void CPlayerInterface::playerStartsTurn(PlayerColor player)
 	}
 
 	// remove all dialogs that do not expect query answer
-	while (GH.windows().topWindow() != adventureInt && !dynamic_cast<CInfoWindow*>(GH.windows().topWindow().get()))
+	while (!GH.windows().topWindow<AdventureMapInterface>() && !GH.windows().topWindow<CInfoWindow>())
 		GH.windows().popWindows(1);
 
 	if (player != playerID && LOCPLINT == this)
@@ -247,7 +247,7 @@ void CPlayerInterface::acceptTurn()
 {
 	if (settings["session"]["autoSkip"].Bool())
 	{
-		while(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.windows().topWindow().get()))
+		while(auto iw = GH.windows().topWindow<CInfoWindow>())
 			iw->close();
 	}
 
@@ -449,7 +449,7 @@ void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, int
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	if (which == 4)
 	{
-		if (CAltarWindow *ctw = dynamic_cast<CAltarWindow *>(GH.windows().topWindow().get()))
+		for (auto ctw : GH.windows().findWindows<CAltarWindow>())
 			ctw->setExpToLevel();
 	}
 	else
@@ -459,11 +459,8 @@ void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, int
 void CPlayerInterface::heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	CUniversityWindow* cuw = dynamic_cast<CUniversityWindow*>(GH.windows().topWindow().get());
-	if (cuw) //university window is open
-	{
-		GH.windows().totalRedraw();
-	}
+	for (auto cuw : GH.windows().findWindows<CUniversityWindow>())
+		cuw->redraw();
 }
 
 void CPlayerInterface::heroManaPointsChanged(const CGHeroInstance * hero)
@@ -482,7 +479,7 @@ void CPlayerInterface::heroMovePointsChanged(const CGHeroInstance * hero)
 void CPlayerInterface::receivedResource()
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if (CMarketplaceWindow *mw = dynamic_cast<CMarketplaceWindow *>(GH.windows().topWindow().get()))
+	for (auto mw : GH.windows().findWindows<CMarketplaceWindow>())
 		mw->resourceChanged();
 
 	GH.windows().totalRedraw();
@@ -1193,12 +1190,10 @@ void CPlayerInterface::availableCreaturesChanged( const CGDwelling *town )
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	if (const CGTownInstance * townObj = dynamic_cast<const CGTownInstance*>(town))
 	{
-		CFortScreen * fortScreen = dynamic_cast<CFortScreen*>(GH.windows().topWindow().get());
-		CCastleInterface * castleInterface = dynamic_cast<CCastleInterface*>(GH.windows().topWindow().get());
-
-		if (fortScreen)
+		for (auto fortScreen : GH.windows().findWindows<CFortScreen>())
 			fortScreen->creaturesChangedEventHandler();
-		else if(castleInterface)
+
+		for (auto castleInterface : GH.windows().findWindows<CCastleInterface>())
 			castleInterface->creaturesChangedEventHandler();
 
 		if (townObj)
@@ -1208,9 +1203,9 @@ void CPlayerInterface::availableCreaturesChanged( const CGDwelling *town )
 	else if(town && GH.windows().count() > 0 && (town->ID == Obj::CREATURE_GENERATOR1
 		||  town->ID == Obj::CREATURE_GENERATOR4  ||  town->ID == Obj::WAR_MACHINE_FACTORY))
 	{
-		CRecruitmentWindow *crw = dynamic_cast<CRecruitmentWindow*>(GH.windows().topWindow().get());
-		if (crw && crw->dwelling == town)
-			crw->availableCreaturesChanged();
+		for (auto crw : GH.windows().findWindows<CRecruitmentWindow>())
+			if (crw->dwelling == town)
+				crw->availableCreaturesChanged();
 	}
 }
 
@@ -1644,7 +1639,7 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 
-	if(dynamic_cast<CSpellWindow *>(GH.windows().topWindow().get()))
+	if(GH.windows().topWindow<CSpellWindow>())
 		GH.windows().popWindows(1);
 
 	if(spellID == SpellID::FLY || spellID == SpellID::WATER_WALK)
@@ -1731,7 +1726,7 @@ void CPlayerInterface::showHillFortWindow(const CGObjectInstance *object, const
 void CPlayerInterface::availableArtifactsChanged(const CGBlackMarket * bm)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if (CMarketplaceWindow *cmw = dynamic_cast<CMarketplaceWindow*>(GH.windows().topWindow().get()))
+	for (auto cmw : GH.windows().findWindows<CMarketplaceWindow>())
 		cmw->artifactsChanged(false);
 }
 

+ 2 - 1
client/CServerHandler.cpp

@@ -750,8 +750,9 @@ void CServerHandler::debugStartTest(std::string filename, bool save)
 
 	boost::this_thread::sleep(boost::posix_time::milliseconds(100));
 
-	while(!settings["session"]["headless"].Bool() && !dynamic_cast<CLobbyScreen *>(GH.windows().topWindow().get()))
+	while(!settings["session"]["headless"].Bool() && !GH.windows().topWindow<CLobbyScreen>())
 		boost::this_thread::sleep(boost::posix_time::milliseconds(50));
+
 	while(!mi || mapInfo->fileURI != CSH->mi->fileURI)
 	{
 		setMapInfo(mapInfo);

+ 1 - 4
client/Client.cpp

@@ -767,11 +767,8 @@ void CClient::removeGUI()
 {
 	// CClient::endGame
 	GH.curInt = nullptr;
-	if(GH.windows().topWindow())
-		GH.windows().topWindow()->deactivate();
-	adventureInt.reset();
 	GH.windows().clear();
-	GH.statusbar.reset();
+	adventureInt.reset();
 	logGlobal->info("Removed GUI.");
 
 	LOCPLINT = nullptr;

+ 5 - 5
client/adventureMap/AdventureMapInterface.cpp

@@ -396,7 +396,7 @@ void AdventureMapInterface::onPlayerTurnStarted(PlayerColor playerID)
 
 	if(settings["session"]["autoSkip"].Bool() && !GH.isKeyboardShiftDown())
 	{
-		if(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.windows().topWindow().get()))
+		if(auto iw = GH.windows().topWindow<CInfoWindow>())
 			iw->close();
 
 		hotkeyEndingTurn();
@@ -528,7 +528,7 @@ void AdventureMapInterface::onTileHovered(const int3 &mapPos)
 	if(!LOCPLINT->cb->isVisible(mapPos))
 	{
 		CCS->curh->set(Cursor::Map::POINTER);
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 		return;
 	}
 	auto objRelations = PlayerRelations::ALLIES;
@@ -538,12 +538,12 @@ void AdventureMapInterface::onTileHovered(const int3 &mapPos)
 		objRelations = LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner);
 		std::string text = LOCPLINT->localState->getCurrentHero() ? objAtTile->getHoverText(LOCPLINT->localState->getCurrentHero()) : objAtTile->getHoverText(LOCPLINT->playerID);
 		boost::replace_all(text,"\n"," ");
-		GH.statusbar->write(text);
+		GH.statusbar()->write(text);
 	}
 	else
 	{
 		std::string hlp = CGI->mh->getTerrainDescr(mapPos, false);
-		GH.statusbar->write(hlp);
+		GH.statusbar()->write(hlp);
 	}
 
 	if(spellBeingCasted)
@@ -680,7 +680,7 @@ void AdventureMapInterface::showMoveDetailsInStatusbar(const CGHeroInstance & he
 	boost::replace_first(result, "%POINTS", std::to_string(movementPointsLastTurnCost));
 	boost::replace_first(result, "%REMAINING", std::to_string(remainingPointsAfterMove));
 
-	GH.statusbar->write(result);
+	GH.statusbar()->write(result);
 }
 
 void AdventureMapInterface::onTileRightClicked(const int3 &mapPos)

+ 3 - 4
client/adventureMap/CInGameConsole.cpp

@@ -217,16 +217,15 @@ void CInGameConsole::startEnteringText()
 	if (captureAllKeys)
 		return;
 
-	assert(GH.statusbar);
 	assert(currentStatusBar.expired());//effectively, nullptr check
 
-	currentStatusBar = GH.statusbar;
+	currentStatusBar = GH.statusbar();
 
 	captureAllKeys = true;
 	enteredText = "_";
 
-	GH.statusbar->setEnteringMode(true);
-	GH.statusbar->setEnteredText(enteredText);
+	GH.statusbar()->setEnteringMode(true);
+	GH.statusbar()->setEnteredText(enteredText);
 }
 
 void CInGameConsole::endEnteringText(bool processEnteredText)

+ 3 - 3
client/adventureMap/CInfoBar.cpp

@@ -262,7 +262,7 @@ void CInfoBar::tick(uint32_t msPassed)
 	{
 		timerCounter = 0;
 		removeUsedEvents(TIME);
-		if(GH.windows().topWindow() == adventureInt)
+		if(GH.windows().isTopWindow(adventureInt))
 			popComponents(true);
 	}
 	else
@@ -293,9 +293,9 @@ void CInfoBar::clickRight(tribool down, bool previousState)
 void CInfoBar::hover(bool on)
 {
 	if(on)
-		GH.statusbar->write(CGI->generaltexth->zelp[292].first);
+		GH.statusbar()->write(CGI->generaltexth->zelp[292].first);
 	else
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 }
 
 CInfoBar::CInfoBar(const Rect & position)

+ 2 - 2
client/adventureMap/CList.cpp

@@ -68,9 +68,9 @@ void CList::CListItem::clickLeft(tribool down, bool previousState)
 void CList::CListItem::hover(bool on)
 {
 	if (on)
-		GH.statusbar->write(getHoverText());
+		GH.statusbar()->write(getHoverText());
 	else
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 }
 
 void CList::CListItem::onSelect(bool on)

+ 2 - 2
client/adventureMap/CMinimap.cpp

@@ -152,9 +152,9 @@ void CMinimap::clickRight(tribool down, bool previousState)
 void CMinimap::hover(bool on)
 {
 	if(on)
-		GH.statusbar->write(CGI->generaltexth->zelp[291].first);
+		GH.statusbar()->write(CGI->generaltexth->zelp[291].first);
 	else
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 }
 
 void CMinimap::mouseMoved(const Point & cursorPosition)

+ 6 - 6
client/battle/BattleActionsController.cpp

@@ -773,7 +773,7 @@ void BattleActionsController::onHexHovered(BattleHex hoveredHex)
 	if (owner.openingPlaying())
 	{
 		currentConsoleMsg = VLC->generaltexth->translate("vcmi.battleWindow.pressKeyToSkipIntro");
-		GH.statusbar->write(currentConsoleMsg);
+		GH.statusbar()->write(currentConsoleMsg);
 		return;
 	}
 
@@ -783,7 +783,7 @@ void BattleActionsController::onHexHovered(BattleHex hoveredHex)
 	if (hoveredHex == BattleHex::INVALID)
 	{
 		if (!currentConsoleMsg.empty())
-			GH.statusbar->clearIfMatching(currentConsoleMsg);
+			GH.statusbar()->clearIfMatching(currentConsoleMsg);
 
 		currentConsoleMsg.clear();
 		CCS->curh->set(Cursor::Combat::BLOCKED);
@@ -806,10 +806,10 @@ void BattleActionsController::onHexHovered(BattleHex hoveredHex)
 	}
 
 	if (!currentConsoleMsg.empty())
-		GH.statusbar->clearIfMatching(currentConsoleMsg);
+		GH.statusbar()->clearIfMatching(currentConsoleMsg);
 
 	if (!newConsoleMsg.empty())
-		GH.statusbar->write(newConsoleMsg);
+		GH.statusbar()->write(newConsoleMsg);
 
 	currentConsoleMsg = newConsoleMsg;
 }
@@ -819,7 +819,7 @@ void BattleActionsController::onHoverEnded()
 	CCS->curh->set(Cursor::Combat::POINTER);
 
 	if (!currentConsoleMsg.empty())
-		GH.statusbar->clearIfMatching(currentConsoleMsg);
+		GH.statusbar()->clearIfMatching(currentConsoleMsg);
 
 	currentConsoleMsg.clear();
 }
@@ -850,7 +850,7 @@ void BattleActionsController::onHexLeftClicked(BattleHex clickedHex)
 	{
 		actionRealize(action, clickedHex);
 
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 	}
 	else
 	{

+ 1 - 1
client/battle/BattleInterfaceClasses.cpp

@@ -592,7 +592,7 @@ void BattleResultWindow::buttonPressed(int button)
 
 	close();
 
-	if(dynamic_cast<BattleWindow*>(GH.windows().topWindow().get()))
+	if(GH.windows().topWindow<BattleWindow>())
 		GH.windows().popWindows(1); //pop battle interface if present
 
 	//Result window and battle interface are gone. We requested all dialogs to be closed before opening the battle,

+ 3 - 2
client/battle/BattleWindow.cpp

@@ -176,13 +176,14 @@ void BattleWindow::updateQueue()
 
 void BattleWindow::activate()
 {
-	GH.statusbar = console;
+	GH.setStatusbar(console);
 	CIntObject::activate();
 	LOCPLINT->cingconsole->activate();
 }
 
 void BattleWindow::deactivate()
 {
+	GH.setStatusbar(nullptr);
 	CIntObject::deactivate();
 	LOCPLINT->cingconsole->deactivate();
 }
@@ -570,7 +571,7 @@ void BattleWindow::show(SDL_Surface *to)
 
 void BattleWindow::close()
 {
-	if(GH.windows().topWindow().get() != this)
+	if(!GH.windows().isTopWindow(this))
 		logGlobal->error("Only top interface must be closed");
 	GH.windows().popWindows(1);
 }

+ 16 - 1
client/gui/CGuiHandler.cpp

@@ -631,7 +631,7 @@ CGuiHandler::CGuiHandler()
 	, mouseButtonsMask(0)
 	, continueEventHandling(true)
 	, curInt(nullptr)
-	, statusbar(nullptr)
+	, fakeStatusBar(std::make_shared<EmptyStatusBar>())
 	, terminate_cond (new CondSh<bool>(false))
 {
 }
@@ -748,6 +748,21 @@ WindowHandler & CGuiHandler::windows()
 	return *windowHandlerInstance;
 }
 
+std::shared_ptr<IStatusBar> CGuiHandler::statusbar()
+{
+	auto locked = currentStatusBar.lock();
+
+	if (!locked)
+		return fakeStatusBar;
+
+	return locked;
+}
+
+void CGuiHandler::setStatusbar(std::shared_ptr<IStatusBar> newStatusBar)
+{
+	currentStatusBar = newStatusBar;
+}
+
 void CGuiHandler::onScreenResize()
 {
 	screenHandler().onScreenResize();

+ 12 - 1
client/gui/CGuiHandler.h

@@ -50,9 +50,14 @@ class CGuiHandler
 {
 public:
 
-	std::shared_ptr<IStatusBar> statusbar;
 
 private:
+	/// Fake no-op version status bar, for use in windows that have no status bar
+	std::shared_ptr<IStatusBar> fakeStatusBar;
+
+	/// Status bar of current window, if any. Uses weak_ptr to allow potential hanging reference after owned window has been deleted
+	std::weak_ptr<IStatusBar> currentStatusBar;
+
 	Point cursorPosition;
 	uint32_t mouseButtonsMask;
 
@@ -122,6 +127,12 @@ public:
 
 	WindowHandler & windows();
 
+	/// Returns currently active status bar. Guaranteed to be non-null
+	std::shared_ptr<IStatusBar> statusbar();
+
+	/// Set currently active status bar
+	void setStatusbar(std::shared_ptr<IStatusBar>);
+
 	IUpdateable *curInt;
 
 	Point lastClick;

+ 1 - 1
client/gui/CIntObject.cpp

@@ -357,7 +357,7 @@ WindowBase::WindowBase(int used_, Point pos_)
 
 void WindowBase::close()
 {
-	if(GH.windows().topWindow().get() != this)
+	if(!GH.windows().isTopWindow(this))
 		logGlobal->error("Only top interface must be closed");
 	GH.windows().popWindows(1);
 }

+ 9 - 0
client/gui/CIntObject.h

@@ -231,3 +231,12 @@ public:
 	virtual void setEnteredText(const std::string & text) = 0;
 
 };
+
+class EmptyStatusBar : public IStatusBar
+{
+	virtual void write(const std::string & text){};
+	virtual void clear(){};
+	virtual void clearIfMatching(const std::string & testedText){};
+	virtual void setEnteringMode(bool on){};
+	virtual void setEnteredText(const std::string & text){};
+};

+ 16 - 1
client/gui/WindowHandler.cpp

@@ -68,7 +68,7 @@ void WindowHandler::popWindows(int howMany)
 	GH.fakeMouseMove();
 }
 
-std::shared_ptr<IShowActivatable> WindowHandler::topWindow() const
+std::shared_ptr<IShowActivatable> WindowHandler::topWindowImpl() const
 {
 	if(windowsStack.empty())
 		return nullptr;
@@ -76,6 +76,18 @@ std::shared_ptr<IShowActivatable> WindowHandler::topWindow() const
 	return windowsStack.back();
 }
 
+bool WindowHandler::isTopWindow(std::shared_ptr<IShowActivatable> window) const
+{
+	assert(window != nullptr);
+	return !windowsStack.empty() && windowsStack.back() == window;
+}
+
+bool WindowHandler::isTopWindow(IShowActivatable * window) const
+{
+	assert(window != nullptr);
+	return !windowsStack.empty() && windowsStack.back().get() == window;
+}
+
 void WindowHandler::totalRedraw()
 {
 	CSDL_Ext::fillSurface(screen2, Colors::BLACK);
@@ -118,6 +130,9 @@ size_t WindowHandler::count() const
 
 void WindowHandler::clear()
 {
+	if(!windowsStack.empty())
+		windowsStack.back()->deactivate();
+
 	windowsStack.clear();
 	disposed.clear();
 }

+ 17 - 3
client/gui/WindowHandler.h

@@ -20,6 +20,9 @@ class WindowHandler
 	/// Temporary list of recently popped windows
 	std::vector<std::shared_ptr<IShowActivatable>> disposed;
 
+	/// returns top windows
+	std::shared_ptr<IShowActivatable> topWindowImpl() const;
+
 public:
 	/// forces total redraw (using showAll), sets a flag, method gets called at the end of the rendering
 	void totalRedraw();
@@ -43,8 +46,13 @@ public:
 	/// removes given windows from the top and activates next
 	void popWindow(std::shared_ptr<IShowActivatable> top);
 
-	/// returns top windows
-	std::shared_ptr<IShowActivatable> topWindow() const;
+	/// returns true if selected interface is on top
+	bool isTopWindow(std::shared_ptr<IShowActivatable> window) const;
+	bool isTopWindow(IShowActivatable * window) const;
+
+	/// returns top window if it matches requested class
+	template <typename T>
+	std::shared_ptr<T> topWindow() const;
 
 	/// should be called after frame has been rendered to screen
 	void onFrameRendered();
@@ -72,7 +80,7 @@ std::vector<std::shared_ptr<T>> WindowHandler::findWindows() const
 {
 	std::vector<std::shared_ptr<T>> result;
 
-	for (auto const & window : windowsStack)
+	for(const auto & window : windowsStack)
 	{
 		std::shared_ptr<T> casted = std::dynamic_pointer_cast<T>(window);
 
@@ -81,3 +89,9 @@ std::vector<std::shared_ptr<T>> WindowHandler::findWindows() const
 	}
 	return result;
 }
+
+template <typename T>
+std::shared_ptr<T> WindowHandler::topWindow() const
+{
+	return std::dynamic_pointer_cast<T>(topWindowImpl());
+}

+ 8 - 8
client/lobby/RandomMapTab.cpp

@@ -483,8 +483,8 @@ void TemplatesDropBox::clickLeft(tribool down, bool previousState)
 		// pop the interface only if the mouse is not clicking on the slider
 		if (!w || !w->mouseState(MouseButton::LEFT))
 		{
-			assert(GH.windows().topWindow().get() == this);
-			GH.windows().popWindow(GH.windows().topWindow());
+			assert(GH.windows().isTopWindow(this));
+			GH.windows().popWindows(1);
 		}
 	}
 }
@@ -512,8 +512,8 @@ void TemplatesDropBox::updateListItems()
 void TemplatesDropBox::setTemplate(const CRmgTemplate * tmpl)
 {
 	randomMapTab.setTemplate(tmpl);
-	assert(GH.windows().topWindow().get() == this);
-	GH.windows().popWindow(GH.windows().topWindow());
+	assert(GH.windows().isTopWindow(this));
+	GH.windows().popWindows(1);
 }
 
 TeamAlignmentsWidget::TeamAlignmentsWidget(RandomMapTab & randomMapTab):
@@ -548,14 +548,14 @@ TeamAlignmentsWidget::TeamAlignmentsWidget(RandomMapTab & randomMapTab):
 			randomMapTab.obtainMapGenOptions().setPlayerTeam(PlayerColor(plId), TeamID(players[plId]->getSelected()));
 		}
 		randomMapTab.updateMapInfoByHost();
-		assert(GH.windows().topWindow().get() == this);
-		GH.windows().popWindow(GH.windows().topWindow());
+		assert(GH.windows().isTopWindow(this));
+		GH.windows().popWindows(1);
 	});
 	
 	addCallback("cancel", [&](int)
 	{
-		assert(GH.windows().topWindow().get() == this);
-		GH.windows().popWindow(GH.windows().topWindow());
+		assert(GH.windows().isTopWindow(this));
+		GH.windows().popWindows(1);
 	});
 	
 	build(config);

+ 4 - 4
client/mainmenu/CMainMenu.cpp

@@ -338,8 +338,8 @@ void CMainMenu::update()
 
 	// check for null othervice crash on finishing a campaign
 	// /FIXME: find out why GH.windows().listInt is empty to begin with
-	if(GH.windows().topWindow())
-		GH.windows().topWindow()->show(screen);
+	if(GH.windows().topWindow<CIntObject>())
+		GH.windows().topWindow<CIntObject>()->show(screen);
 }
 
 void CMainMenu::openLobby(ESelectionScreen screenType, bool host, const std::vector<std::string> * names, ELoadMode loadMode)
@@ -523,7 +523,7 @@ void CSimpleJoinScreen::leaveScreen()
 		textTitle->setText("Closing...");
 		CSH->state = EClientState::CONNECTION_CANCELLED;
 	}
-	else if(GH.windows().topWindow().get() == this)
+	else if(GH.windows().isTopWindow(this))
 	{
 		close();
 	}
@@ -553,7 +553,7 @@ void CSimpleJoinScreen::connectThread(const std::string & addr, ui16 port)
 	else
 		CSH->justConnectToServer(addr, port);
 
-	if(GH.windows().topWindow().get() == this)
+	if(GH.windows().isTopWindow(this))
 	{
 		close();
 	}

+ 1 - 1
client/mapView/MapViewActions.cpp

@@ -154,7 +154,7 @@ void MapViewActions::hover(bool on)
 {
 	if(!on)
 	{
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 		CCS->curh->set(Cursor::Map::POINTER);
 	}
 }

+ 2 - 2
client/mapView/MapViewController.cpp

@@ -209,7 +209,7 @@ bool MapViewController::isEventVisible(const CGObjectInstance * obj)
 	if(!LOCPLINT->makingTurn && settings["adventure"]["enemyMoveTime"].Float() < 0)
 		return false; // enemy move speed set to "hidden/none"
 
-	if(GH.windows().topWindow() != adventureInt)
+	if(!GH.windows().isTopWindow(adventureInt))
 		return false;
 
 	if(obj->isVisitable())
@@ -226,7 +226,7 @@ bool MapViewController::isEventVisible(const CGHeroInstance * obj, const int3 &
 	if(!LOCPLINT->makingTurn && settings["adventure"]["enemyMoveTime"].Float() < 0)
 		return false; // enemy move speed set to "hidden/none"
 
-	if(GH.windows().topWindow() != adventureInt)
+	if(!GH.windows().isTopWindow(adventureInt))
 		return false;
 
 	if(context->isVisible(obj->convertToVisitablePos(from)))

+ 0 - 1
client/renderSDL/ScreenHandler.cpp

@@ -330,7 +330,6 @@ SDL_Window * ScreenHandler::createWindow()
 void ScreenHandler::onScreenResize()
 {
 	recreateWindowAndScreenBuffers();
-	GH.onScreenResize();
 }
 
 void ScreenHandler::validateSettings()

+ 4 - 4
client/widgets/Buttons.cpp

@@ -218,9 +218,9 @@ void CButton::hover (bool on)
 	if(!name.empty() && !isBlocked()) //if there is no name, there is nothing to display also
 	{
 		if (on)
-			GH.statusbar->write(name);
+			GH.statusbar()->write(name);
 		else
-			GH.statusbar->clearIfMatching(name);
+			GH.statusbar()->clearIfMatching(name);
 	}
 }
 
@@ -532,8 +532,8 @@ void CVolumeSlider::clickRight(tribool down, bool previousState)
 
 		if(!helpBox.empty())
 			CRClickPopup::createAndPush(helpBox);
-		if(GH.statusbar)
-			GH.statusbar->write(helpBox);
+
+		GH.statusbar()->write(helpBox);
 	}
 }
 

+ 3 - 3
client/widgets/CGarrisonInt.cpp

@@ -116,11 +116,11 @@ void CGarrisonSlot::hover (bool on)
 				temp = CGI->generaltexth->tcommands[11]; //Empty
 			}
 		}
-		GH.statusbar->write(temp);
+		GH.statusbar()->write(temp);
 	}
 	else
 	{
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 	}
 }
 
@@ -184,7 +184,7 @@ bool CGarrisonSlot::viewInfo()
 bool CGarrisonSlot::highlightOrDropArtifact()
 {
 	bool artSelected = false;
-	if (CWindowWithArtifacts* chw = dynamic_cast<CWindowWithArtifacts*>(GH.windows().topWindow().get())) //dirty solution
+	if (auto chw = GH.windows().topWindow<CWindowWithArtifacts>()) //dirty solution
 	{
 		const auto pickedArtInst = chw->getPickedArtifact();
 

+ 4 - 4
client/widgets/MiscWidgets.cpp

@@ -36,9 +36,9 @@
 void CHoverableArea::hover (bool on)
 {
 	if (on)
-		GH.statusbar->write(hoverText);
+		GH.statusbar()->write(hoverText);
 	else
-		GH.statusbar->clearIfMatching(hoverText);
+		GH.statusbar()->clearIfMatching(hoverText);
 }
 
 CHoverableArea::CHoverableArea()
@@ -152,9 +152,9 @@ void CHeroArea::clickRight(tribool down, bool previousState)
 void CHeroArea::hover(bool on)
 {
 	if (on && hero)
-		GH.statusbar->write(hero->getObjectName());
+		GH.statusbar()->write(hero->getObjectName());
 	else
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 }
 
 void LRClickableAreaOpenTown::clickLeft(tribool down, bool previousState)

+ 4 - 5
client/widgets/TextControls.cpp

@@ -434,9 +434,7 @@ CGStatusBar::CGStatusBar(int x, int y, std::string name, int maxw)
 
 CGStatusBar::~CGStatusBar()
 {
-	assert(GH.statusbar.get() != this || GH.statusbar == nullptr);
-	if (GH.statusbar.get() == this)
-		GH.statusbar = nullptr;
+	assert(GH.statusbar().get() != this);
 }
 
 void CGStatusBar::show(SDL_Surface * to)
@@ -455,13 +453,14 @@ void CGStatusBar::clickLeft(tribool down, bool previousState)
 
 void CGStatusBar::activate()
 {
-	GH.statusbar = shared_from_this();
+	GH.setStatusbar(shared_from_this());
 	CIntObject::activate();
 }
 
 void CGStatusBar::deactivate()
 {
-	assert(GH.statusbar.get() == this);
+	assert(GH.statusbar().get() == this);
+	GH.setStatusbar(nullptr);
 
 	if (enteringText)
 		LOCPLINT->cingconsole->endEnteringText(false);

+ 19 - 18
client/windows/CCastleInterface.cpp

@@ -126,7 +126,7 @@ void CBuildingRect::hover(bool on)
 		if(parent->selectedBuilding == this)
 		{
 			parent->selectedBuilding = nullptr;
-			GH.statusbar->clear();
+			GH.statusbar()->clear();
 		}
 	}
 }
@@ -256,7 +256,7 @@ void CBuildingRect::mouseMoved (const Point & cursorPosition)
 			if(parent->selectedBuilding == this)
 			{
 				parent->selectedBuilding = nullptr;
-				GH.statusbar->clear();
+				GH.statusbar()->clear();
 			}
 		}
 		else //inside the area of this building
@@ -265,7 +265,7 @@ void CBuildingRect::mouseMoved (const Point & cursorPosition)
 			  || (*parent->selectedBuilding)<(*this)) //or we are on top
 			{
 				parent->selectedBuilding = this;
-				GH.statusbar->write(getSubtitle());
+				GH.statusbar()->write(getSubtitle());
 			}
 		}
 	}
@@ -339,7 +339,7 @@ void CHeroGSlot::hover(bool on)
 {
 	if(!on)
 	{
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 		return;
 	}
 	std::shared_ptr<CHeroGSlot> other = upg ? owner->garrisonedHero : owner->visitingHero;
@@ -384,7 +384,7 @@ void CHeroGSlot::hover(bool on)
 		}
 	}
 	if(temp.size())
-		GH.statusbar->write(temp);
+		GH.statusbar()->write(temp);
 }
 
 void CHeroGSlot::clickLeft(tribool down, bool previousState)
@@ -974,7 +974,8 @@ void CCastleBuildings::enterTownHall()
 		else
 		{
 			LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[673]);
-			dynamic_cast<CInfoWindow*>(GH.windows().topWindow().get())->buttons[0]->addCallback(std::bind(&CCastleBuildings::openTownHall, this));
+			assert(GH.windows().topWindow<CInfoWindow>() != nullptr);
+			GH.windows().topWindow<CInfoWindow>()->buttons[0]->addCallback(std::bind(&CCastleBuildings::openTownHall, this));
 		}
 	}
 	else
@@ -1058,11 +1059,11 @@ void CCreaInfo::hover(bool on)
 
 	if(on)
 	{
-		GH.statusbar->write(message);
+		GH.statusbar()->write(message);
 	}
 	else
 	{
-		GH.statusbar->clearIfMatching(message);
+		GH.statusbar()->clearIfMatching(message);
 	}
 }
 
@@ -1137,11 +1138,11 @@ void CTownInfo::hover(bool on)
 	if(on)
 	{
 		if(building )
-			GH.statusbar->write(building->getNameTranslated());
+			GH.statusbar()->write(building->getNameTranslated());
 	}
 	else
 	{
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 	}
 }
 
@@ -1383,11 +1384,11 @@ void CHallInterface::CBuildingBox::hover(bool on)
 		else
 			toPrint = CGI->generaltexth->hcommands[state];
 		boost::algorithm::replace_first(toPrint,"%s",building->getNameTranslated());
-		GH.statusbar->write(toPrint);
+		GH.statusbar()->write(toPrint);
 	}
 	else
 	{
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 	}
 }
 
@@ -1571,11 +1572,11 @@ void LabeledValue::hover(bool on)
 {
 	if(on)
 	{
-		GH.statusbar->write(hoverText);
+		GH.statusbar()->write(hoverText);
 	}
 	else
 	{
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 		parent->hovered = false;
 	}
 }
@@ -1740,9 +1741,9 @@ const CBuilding * CFortScreen::RecruitArea::getMyBuilding()
 void CFortScreen::RecruitArea::hover(bool on)
 {
 	if(on)
-		GH.statusbar->write(hoverText);
+		GH.statusbar()->write(hoverText);
 	else
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 }
 
 void CFortScreen::RecruitArea::creaturesChangedEventHandler()
@@ -1830,9 +1831,9 @@ void CMageGuildScreen::Scroll::clickRight(tribool down, bool previousState)
 void CMageGuildScreen::Scroll::hover(bool on)
 {
 	if(on)
-		GH.statusbar->write(spell->getNameTranslated());
+		GH.statusbar()->write(spell->getNameTranslated());
 	else
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 
 }
 

+ 4 - 4
client/windows/CTradeWindow.cpp

@@ -243,7 +243,7 @@ void CTradeWindow::CTradeableItem::hover(bool on)
 {
 	if(!on)
 	{
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 		return;
 	}
 
@@ -251,13 +251,13 @@ void CTradeWindow::CTradeableItem::hover(bool on)
 	{
 	case CREATURE:
 	case CREATURE_PLACEHOLDER:
-		GH.statusbar->write(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->objects[id]->getNamePluralTranslated()));
+		GH.statusbar()->write(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->objects[id]->getNamePluralTranslated()));
 		break;
 	case ARTIFACT_PLACEHOLDER:
 		if(id < 0)
-			GH.statusbar->write(CGI->generaltexth->zelp[582].first);
+			GH.statusbar()->write(CGI->generaltexth->zelp[582].first);
 		else
-			GH.statusbar->write(CGI->artifacts()->getByIndex(id)->getNameTranslated());
+			GH.statusbar()->write(CGI->artifacts()->getByIndex(id)->getNameTranslated());
 		break;
 	}
 }

+ 4 - 4
client/windows/GUIClasses.cpp

@@ -586,9 +586,9 @@ void CTavernWindow::HeroPortrait::hover(bool on)
 {
 	//Hoverable::hover(on);
 	if(on)
-		GH.statusbar->write(hoverName);
+		GH.statusbar()->write(hoverName);
 	else
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 }
 
 static const std::string QUICK_EXCHANGE_MOD_PREFIX = "quick-exchange";
@@ -1256,9 +1256,9 @@ void CUniversityWindow::CItem::clickRight(tribool down, bool previousState)
 void CUniversityWindow::CItem::hover(bool on)
 {
 	if(on)
-		GH.statusbar->write(CGI->skillh->getByIndex(ID)->getNameTranslated());
+		GH.statusbar()->write(CGI->skillh->getByIndex(ID)->getNameTranslated());
 	else
-		GH.statusbar->clear();
+		GH.statusbar()->clear();
 }
 
 int CUniversityWindow::CItem::state()

+ 1 - 1
client/windows/settings/SettingsMainWindow.cpp

@@ -104,7 +104,7 @@ void SettingsMainWindow::openTab(size_t index)
 
 void SettingsMainWindow::close()
 {
-	if(GH.windows().topWindow().get() != this)
+	if(!GH.windows().isTopWindow(this))
 		logGlobal->error("Only top interface must be closed");
 	GH.windows().popWindows(1);
 }