瀏覽代碼

Moved window stack management from GuiHandler to new class

Ivan Savenko 2 年之前
父節點
當前提交
7838190ef4
共有 40 個文件被更改,包括 411 次插入298 次删除
  1. 8 7
      client/CMT.cpp
  2. 2 0
      client/CMakeLists.txt
  3. 55 54
      client/CPlayerInterface.cpp
  4. 3 2
      client/CServerHandler.cpp
  5. 5 4
      client/Client.cpp
  6. 5 4
      client/ClientCommandManager.cpp
  7. 6 5
      client/NetPacksLobbyClient.cpp
  8. 2 1
      client/adventureMap/AdventureMapInterface.cpp
  9. 7 6
      client/adventureMap/AdventureMapShortcuts.cpp
  10. 3 2
      client/adventureMap/AdventureOptions.cpp
  11. 3 2
      client/adventureMap/CInGameConsole.cpp
  12. 2 1
      client/adventureMap/CInfoBar.cpp
  13. 2 1
      client/adventureMap/CMinimap.cpp
  14. 3 2
      client/battle/BattleActionsController.cpp
  15. 4 3
      client/battle/BattleInterface.cpp
  16. 5 4
      client/battle/BattleInterfaceClasses.cpp
  17. 7 6
      client/battle/BattleWindow.cpp
  18. 13 88
      client/gui/CGuiHandler.cpp
  19. 4 22
      client/gui/CGuiHandler.h
  20. 3 2
      client/gui/CIntObject.cpp
  21. 115 0
      client/gui/WindowHandler.cpp
  22. 54 0
      client/gui/WindowHandler.h
  23. 3 2
      client/lobby/CBonusSelection.cpp
  24. 4 3
      client/lobby/CSelectionBase.cpp
  25. 2 1
      client/lobby/OptionsTab.cpp
  26. 11 10
      client/lobby/RandomMapTab.cpp
  27. 16 15
      client/mainmenu/CMainMenu.cpp
  28. 3 2
      client/mapView/MapViewController.cpp
  29. 2 1
      client/renderSDL/ScreenHandler.cpp
  30. 5 4
      client/widgets/CGarrisonInt.cpp
  31. 3 2
      client/widgets/CWindowWithArtifacts.cpp
  32. 22 21
      client/windows/CCastleInterface.cpp
  33. 5 4
      client/windows/CHeroWindow.cpp
  34. 2 1
      client/windows/CSpellWindow.cpp
  35. 3 2
      client/windows/CTradeWindow.cpp
  36. 2 1
      client/windows/CreaturePurchaseCard.cpp
  37. 5 4
      client/windows/GUIClasses.cpp
  38. 5 4
      client/windows/InfoWindows.cpp
  39. 3 2
      client/windows/settings/GeneralOptionsTab.cpp
  40. 4 3
      client/windows/settings/SettingsMainWindow.cpp

+ 8 - 7
client/CMT.cpp

@@ -20,6 +20,7 @@
 #include "CVideoHandler.h"
 #include "CMusicHandler.h"
 #include "gui/CGuiHandler.h"
+#include "gui/WindowHandler.h"
 #include "CServerHandler.h"
 #include "gui/NotificationHandler.h"
 #include "ClientCommandManager.h"
@@ -523,14 +524,14 @@ static void handleEvent(SDL_Event & ev)
 				{
 					if(ourCampaign->mapsRemaining.size())
 					{
-						GH.pushInt(CMM);
-						GH.pushInt(CMM->menu);
+						GH.windows().pushInt(CMM);
+						GH.windows().pushInt(CMM->menu);
 						CMM->openCampaignLobby(ourCampaign);
 					}
 				};
 				if(epilogue.hasPrologEpilog)
 				{
-					GH.pushIntT<CPrologEpilogVideo>(epilogue, finisher);
+					GH.windows().pushIntT<CPrologEpilogVideo>(epilogue, finisher);
 				}
 				else
 				{
@@ -547,7 +548,7 @@ static void handleEvent(SDL_Event & ev)
 		case EUserEvent::FULLSCREEN_TOGGLED:
 			{
 				boost::unique_lock<boost::recursive_mutex> lock(*CPlayerInterface::pim);
-				GH.screenHandler().onScreenResize();
+				GH.onScreenResize();
 				break;
 			}
 		default:
@@ -564,7 +565,7 @@ static void handleEvent(SDL_Event & ev)
 #ifndef VCMI_IOS
 			{
 				boost::unique_lock<boost::recursive_mutex> lock(*CPlayerInterface::pim);
-				GH.screenHandler().onScreenResize();
+				GH.onScreenResize();
 			}
 #endif
 			break;
@@ -622,8 +623,8 @@ static void quitApplication()
 			CSH->endGameplay();
 	}
 
-	GH.listInt.clear();
-	GH.objsToBlit.clear();
+	GH.windows().listInt.clear();
+	GH.windows().objsToBlit.clear();
 
 	CMM.reset();
 

+ 2 - 0
client/CMakeLists.txt

@@ -34,6 +34,7 @@ set(client_SRCS
 	gui/FramerateManager.cpp
 	gui/NotificationHandler.cpp
 	gui/ShortcutHandler.cpp
+	gui/WindowHandler.cpp
 
 	lobby/CBonusSelection.cpp
 	lobby/CCampaignInfoScreen.cpp
@@ -169,6 +170,7 @@ set(client_HEADERS
 	gui/Shortcut.h
 	gui/ShortcutHandler.h
 	gui/TextAlignment.h
+	gui/WindowHandler.h
 
 	lobby/CBonusSelection.h
 	lobby/CCampaignInfoScreen.h

+ 55 - 54
client/CPlayerInterface.cpp

@@ -65,6 +65,7 @@
 #include "../lib/CPlayerState.h"
 #include "../lib/GameConstants.h"
 #include "gui/CGuiHandler.h"
+#include "gui/WindowHandler.h"
 #include "windows/InfoWindows.h"
 #include "../lib/UnlockGuard.h"
 #include "../lib/CPathfinder.h"
@@ -168,16 +169,16 @@ void CPlayerInterface::initGameInterface(std::shared_ptr<Environment> ENV, std::
 void CPlayerInterface::playerStartsTurn(PlayerColor player)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if (!vstd::contains (GH.listInt, adventureInt))
+	if (!vstd::contains (GH.windows().listInt, adventureInt))
 	{
 		// after map load - remove all active windows and replace them with adventure map
-		GH.popInts ((int)GH.listInt.size());
-		GH.pushInt (adventureInt);
+		GH.windows().popInts ((int)GH.windows().listInt.size());
+		GH.windows().pushInt (adventureInt);
 	}
 
 	// remove all dialogs that do not expect query answer
-	while (GH.listInt.front() != adventureInt && !dynamic_cast<CInfoWindow*>(GH.listInt.front().get()))
-		GH.popInts(1);
+	while (GH.windows().listInt.front() != adventureInt && !dynamic_cast<CInfoWindow*>(GH.windows().listInt.front().get()))
+		GH.windows().popInts(1);
 
 	if (player != playerID && LOCPLINT == this)
 	{
@@ -245,7 +246,7 @@ void CPlayerInterface::acceptTurn()
 {
 	if (settings["session"]["autoSkip"].Bool())
 	{
-		while(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt().get()))
+		while(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.windows().topInt().get()))
 			iw->close();
 	}
 
@@ -439,7 +440,7 @@ void CPlayerInterface::openTownWindow(const CGTownInstance * town)
 
 	auto newCastleInt = std::make_shared<CCastleInterface>(town);
 
-	GH.pushInt(newCastleInt);
+	GH.windows().pushInt(newCastleInt);
 }
 
 void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val)
@@ -447,7 +448,7 @@ void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, int
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	if (which == 4)
 	{
-		if (CAltarWindow *ctw = dynamic_cast<CAltarWindow *>(GH.topInt().get()))
+		if (CAltarWindow *ctw = dynamic_cast<CAltarWindow *>(GH.windows().topInt().get()))
 			ctw->setExpToLevel();
 	}
 	else
@@ -457,10 +458,10 @@ 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.topInt().get());
+	CUniversityWindow* cuw = dynamic_cast<CUniversityWindow*>(GH.windows().topInt().get());
 	if (cuw) //university window is open
 	{
-		GH.totalRedraw();
+		GH.windows().totalRedraw();
 	}
 }
 
@@ -480,10 +481,10 @@ void CPlayerInterface::heroMovePointsChanged(const CGHeroInstance * hero)
 void CPlayerInterface::receivedResource()
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if (CMarketplaceWindow *mw = dynamic_cast<CMarketplaceWindow *>(GH.topInt().get()))
+	if (CMarketplaceWindow *mw = dynamic_cast<CMarketplaceWindow *>(GH.windows().topInt().get()))
 		mw->resourceChanged();
 
-	GH.totalRedraw();
+	GH.windows().totalRedraw();
 }
 
 void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill>& skills, QueryID queryID)
@@ -491,7 +492,7 @@ void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, PrimarySkill::Pr
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	waitWhileDialog();
 	CCS->soundh->playSound(soundBase::heroNewLevel);
-	GH.pushIntT<CLevelWindow>(hero, pskill, skills, [=](ui32 selection)
+	GH.windows().pushIntT<CLevelWindow>(hero, pskill, skills, [=](ui32 selection)
 	{
 		cb->selectionMade(selection, queryID);
 	});
@@ -502,7 +503,7 @@ void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander,
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	waitWhileDialog();
 	CCS->soundh->playSound(soundBase::heroNewLevel);
-	GH.pushIntT<CStackWindow>(commander, skills, [=](ui32 selection)
+	GH.windows().pushIntT<CStackWindow>(commander, skills, [=](ui32 selection)
 	{
 		cb->selectionMade(selection, queryID);
 	});
@@ -537,7 +538,7 @@ void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
 		castleInt->heroes->update();
 		castleInt->redraw();
 	}
-	for (auto isa : GH.listInt)
+	for (auto isa : GH.windows().listInt)
 	{
 		CKingdomInterface *ki = dynamic_cast<CKingdomInterface*>(isa.get());
 		if (ki)
@@ -589,7 +590,7 @@ void CPlayerInterface::garrisonsChanged(std::vector<const CGObjectInstance *> ob
 			adventureInt->onTownChanged(town);
 	}
 
-	for (auto & elem : GH.listInt)
+	for (auto & elem : GH.windows().listInt)
 	{
 		CGarrisonHolder *cgh = dynamic_cast<CGarrisonHolder*>(elem.get());
 		if (cgh)
@@ -602,7 +603,7 @@ void CPlayerInterface::garrisonsChanged(std::vector<const CGObjectInstance *> ob
 		}
 	}
 
-	GH.totalRedraw();
+	GH.windows().totalRedraw();
 }
 
 void CPlayerInterface::buildChanged(const CGTownInstance *town, BuildingID buildingID, int what) //what: 1 - built, 2 - demolished
@@ -861,7 +862,7 @@ void CPlayerInterface::battleEnd(const BattleResult *br, QueryID queryID)
 			{
 				cb->selectionMade(selection, queryID);
 			};
-			GH.pushInt(wnd);
+			GH.windows().pushInt(wnd);
 			// #1490 - during AI turn when quick combat is on, we need to display the message and wait for user to close it.
 			// Otherwise NewTurn causes freeze.
 			waitWhileDialog();
@@ -1015,7 +1016,7 @@ void CPlayerInterface::showInfoDialog(EInfoWindowMode type, const std::string &t
 		waitWhileDialog(); //Fix for mantis #98
 		adventureInt->showInfoBoxMessage(components, text, timer);
 
-		if (makingTurn && GH.listInt.size() && LOCPLINT == this)
+		if (makingTurn && GH.windows().listInt.size() && LOCPLINT == this)
 			CCS->soundh->playSound(static_cast<soundBase::soundID>(soundID));
 		return;
 	}
@@ -1056,12 +1057,12 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
 	}
 	std::shared_ptr<CInfoWindow> temp = CInfoWindow::create(text, playerID, components);
 
-	if (makingTurn && GH.listInt.size() && LOCPLINT == this)
+	if (makingTurn && GH.windows().listInt.size() && LOCPLINT == this)
 	{
 		CCS->soundh->playSound(static_cast<soundBase::soundID>(soundID));
 		showingDialog->set(true);
 		stopMovement(); // interrupt movement to show dialog
-		GH.pushInt(temp);
+		GH.windows().pushInt(temp);
 	}
 	else
 	{
@@ -1121,7 +1122,7 @@ void CPlayerInterface::showBlockingDialog( const std::string &text, const std::v
 		int charperline = 35;
 		if (pom.size() > 1)
 			charperline = 50;
-		GH.pushIntT<CSelWindow>(text, playerID, charperline, intComps, pom, askID);
+		GH.windows().pushIntT<CSelWindow>(text, playerID, charperline, intComps, pom, askID);
 		intComps[0]->clickLeft(true, false);
 	}
 }
@@ -1170,7 +1171,7 @@ void CPlayerInterface::showMapObjectSelectDialog(QueryID askID, const Component
 
 	std::shared_ptr<CObjectListWindow> wnd = std::make_shared<CObjectListWindow>(tempList, localIcon, localTitle, localDescription, selectCallback);
 	wnd->onExit = cancelCallback;
-	GH.pushInt(wnd);
+	GH.windows().pushInt(wnd);
 }
 
 void CPlayerInterface::tileRevealed(const std::unordered_set<int3> &pos)
@@ -1189,7 +1190,7 @@ void CPlayerInterface::tileHidden(const std::unordered_set<int3> &pos)
 void CPlayerInterface::openHeroWindow(const CGHeroInstance *hero)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
-	GH.pushIntT<CHeroWindow>(hero);
+	GH.windows().pushIntT<CHeroWindow>(hero);
 }
 
 void CPlayerInterface::availableCreaturesChanged( const CGDwelling *town )
@@ -1197,25 +1198,25 @@ 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.topInt().get());
-		CCastleInterface * castleInterface = dynamic_cast<CCastleInterface*>(GH.topInt().get());
+		CFortScreen * fortScreen = dynamic_cast<CFortScreen*>(GH.windows().topInt().get());
+		CCastleInterface * castleInterface = dynamic_cast<CCastleInterface*>(GH.windows().topInt().get());
 
 		if (fortScreen)
 			fortScreen->creaturesChangedEventHandler();
 		else if(castleInterface)
 			castleInterface->creaturesChangedEventHandler();
 
-		for(auto isa : GH.listInt)
+		for(auto isa : GH.windows().listInt)
 		{
 			CKingdomInterface *ki = dynamic_cast<CKingdomInterface*>(isa.get());
 			if (ki && townObj)
 				ki->townChanged(townObj);
 		}
 	}
-	else if(town && GH.listInt.size() && (town->ID == Obj::CREATURE_GENERATOR1
+	else if(town && GH.windows().listInt.size() && (town->ID == Obj::CREATURE_GENERATOR1
 		||  town->ID == Obj::CREATURE_GENERATOR4  ||  town->ID == Obj::WAR_MACHINE_FACTORY))
 	{
-		CRecruitmentWindow *crw = dynamic_cast<CRecruitmentWindow*>(GH.topInt().get());
+		CRecruitmentWindow *crw = dynamic_cast<CRecruitmentWindow*>(GH.windows().topInt().get());
 		if (crw && crw->dwelling == town)
 			crw->availableCreaturesChanged();
 	}
@@ -1283,7 +1284,7 @@ void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHer
 
 	auto cgw = std::make_shared<CGarrisonWindow>(up, down, removableUnits);
 	cgw->quit->addCallback(onEnd);
-	GH.pushInt(cgw);
+	GH.windows().pushInt(cgw);
 }
 
 /**
@@ -1341,7 +1342,7 @@ void CPlayerInterface::showHeroExchange(ObjectInstanceID hero1, ObjectInstanceID
 void CPlayerInterface::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	GH.pushIntT<CExchangeWindow>(hero1, hero2, query);
+	GH.windows().pushIntT<CExchangeWindow>(hero1, hero2, query);
 }
 
 void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
@@ -1402,7 +1403,7 @@ void CPlayerInterface::showRecruitmentDialog(const CGDwelling *dwelling, const C
 	{
 		LOCPLINT->cb->recruitCreatures(dwelling, dst, id, count, -1);
 	};
-	GH.pushIntT<CRecruitmentWindow>(dwelling, level, dst, recruitCb);
+	GH.windows().pushIntT<CRecruitmentWindow>(dwelling, level, dst, recruitCb);
 }
 
 void CPlayerInterface::waitWhileDialog(bool unlockPim)
@@ -1425,7 +1426,7 @@ void CPlayerInterface::showShipyardDialog(const IShipyard *obj)
 	auto state = obj->shipyardStatus();
 	TResources cost;
 	obj->getBoatCost(cost);
-	GH.pushIntT<CShipyardWindow>(cost, state, obj->getBoatType(), [=](){ cb->buildBoat(obj); });
+	GH.windows().pushIntT<CShipyardWindow>(cost, state, obj->getBoatType(), [=](){ cb->buildBoat(obj); });
 }
 
 void CPlayerInterface::newObject( const CGObjectInstance * obj )
@@ -1449,7 +1450,7 @@ void CPlayerInterface::centerView (int3 pos, int focusTime)
 	adventureInt->centerOnTile(pos);
 	if (focusTime)
 	{
-		GH.totalRedraw();
+		GH.windows().totalRedraw();
 		{
 			auto unlockPim = vstd::makeUnlockGuard(*pim);
 			IgnoreEvents ignore(*this);
@@ -1518,7 +1519,7 @@ void CPlayerInterface::update()
 	if ((CSH->howManyPlayerInterfaces() <= 1 || makingTurn) && !dialogs.empty() && !showingDialog->get())
 	{
 		showingDialog->set(true);
-		GH.pushInt(dialogs.front());
+		GH.windows().pushInt(dialogs.front());
 		dialogs.pop_front();
 	}
 
@@ -1527,7 +1528,7 @@ void CPlayerInterface::update()
 	// Handles mouse and key input
 	GH.updateTime();
 	GH.handleEvents();
-	GH.simpleRedraw();
+	GH.windows().simpleRedraw();
 }
 
 int CPlayerInterface::getLastIndex( std::string namePrefix)
@@ -1593,7 +1594,7 @@ void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResul
 			if(adventureInt)
 			{
 				GH.terminate_cond->setn(true);
-				GH.popInts(GH.listInt.size());
+				GH.windows().popInts(GH.windows().listInt.size());
 				adventureInt.reset();
 			}
 		}
@@ -1639,7 +1640,7 @@ void CPlayerInterface::showPuzzleMap()
 	double ratio = 0;
 	int3 grailPos = cb->getGrailPos(&ratio);
 
-	GH.pushIntT<CPuzzleWindow>(grailPos, ratio);
+	GH.windows().pushIntT<CPuzzleWindow>(grailPos, ratio);
 }
 
 void CPlayerInterface::viewWorldMap()
@@ -1651,8 +1652,8 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 
-	if(dynamic_cast<CSpellWindow *>(GH.topInt().get()))
-		GH.popInts(1);
+	if(dynamic_cast<CSpellWindow *>(GH.windows().topInt().get()))
+		GH.windows().popInts(1);
 
 	if(spellID == SpellID::FLY || spellID == SpellID::WATER_WALK)
 		localState->erasePath(caster);
@@ -1714,50 +1715,50 @@ void CPlayerInterface::showMarketWindow(const IMarket *market, const CGHeroInsta
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 
 	if(market->allowsTrade(EMarketMode::ARTIFACT_EXP) && visitor->getAlignment() != EAlignment::EVIL)
-		GH.pushIntT<CAltarWindow>(market, visitor, EMarketMode::ARTIFACT_EXP);
+		GH.windows().pushIntT<CAltarWindow>(market, visitor, EMarketMode::ARTIFACT_EXP);
 	else if(market->allowsTrade(EMarketMode::CREATURE_EXP) && visitor->getAlignment() != EAlignment::GOOD)
-		GH.pushIntT<CAltarWindow>(market, visitor, EMarketMode::CREATURE_EXP);
+		GH.windows().pushIntT<CAltarWindow>(market, visitor, EMarketMode::CREATURE_EXP);
 	else if(market->allowsTrade(EMarketMode::CREATURE_UNDEAD))
-		GH.pushIntT<CTransformerWindow>(market, visitor);
+		GH.windows().pushIntT<CTransformerWindow>(market, visitor);
 	else if(!market->availableModes().empty())
-		GH.pushIntT<CMarketplaceWindow>(market, visitor, market->availableModes().front());
+		GH.windows().pushIntT<CMarketplaceWindow>(market, visitor, market->availableModes().front());
 }
 
 void CPlayerInterface::showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	GH.pushIntT<CUniversityWindow>(visitor, market);
+	GH.windows().pushIntT<CUniversityWindow>(visitor, market);
 }
 
 void CPlayerInterface::showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	GH.pushIntT<CHillFortWindow>(visitor, object);
+	GH.windows().pushIntT<CHillFortWindow>(visitor, object);
 }
 
 void CPlayerInterface::availableArtifactsChanged(const CGBlackMarket * bm)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if (CMarketplaceWindow *cmw = dynamic_cast<CMarketplaceWindow*>(GH.topInt().get()))
+	if (CMarketplaceWindow *cmw = dynamic_cast<CMarketplaceWindow*>(GH.windows().topInt().get()))
 		cmw->artifactsChanged(false);
 }
 
 void CPlayerInterface::showTavernWindow(const CGObjectInstance *townOrTavern)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	GH.pushIntT<CTavernWindow>(townOrTavern);
+	GH.windows().pushIntT<CTavernWindow>(townOrTavern);
 }
 
 void CPlayerInterface::showThievesGuildWindow (const CGObjectInstance * obj)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	GH.pushIntT<CThievesGuildWindow>(obj);
+	GH.windows().pushIntT<CThievesGuildWindow>(obj);
 }
 
 void CPlayerInterface::showQuestLog()
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	GH.pushIntT<CQuestLog>(LOCPLINT->cb->getMyQuests());
+	GH.windows().pushIntT<CQuestLog>(LOCPLINT->cb->getMyQuests());
 }
 
 void CPlayerInterface::showShipyardDialogOrProblemPopup(const IShipyard *obj)
@@ -1808,7 +1809,7 @@ void CPlayerInterface::artifactRemoved(const ArtifactLocation &al)
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
 	adventureInt->onHeroChanged(hero);
-	for(auto isa : GH.listInt)
+	for(auto isa : GH.windows().listInt)
 	{
 		auto artWin = dynamic_cast<CArtifactHolder*>(isa.get());
 		if (artWin)
@@ -1833,7 +1834,7 @@ void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const Artifact
 			redraw = false;
 	}
 
-	for(auto isa : GH.listInt)
+	for(auto isa : GH.windows().listInt)
 	{
 		auto artWin = dynamic_cast<CArtifactHolder*>(isa.get());
 		if (artWin)
@@ -1852,7 +1853,7 @@ void CPlayerInterface::artifactAssembled(const ArtifactLocation &al)
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
 	adventureInt->onHeroChanged(hero);
-	for(auto isa : GH.listInt)
+	for(auto isa : GH.windows().listInt)
 	{
 		auto artWin = dynamic_cast<CArtifactHolder*>(isa.get());
 		if (artWin)
@@ -1865,7 +1866,7 @@ void CPlayerInterface::artifactDisassembled(const ArtifactLocation &al)
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
 	adventureInt->onHeroChanged(hero);
-	for(auto isa : GH.listInt)
+	for(auto isa : GH.windows().listInt)
 	{
 		auto artWin = dynamic_cast<CArtifactHolder*>(isa.get());
 		if (artWin)

+ 3 - 2
client/CServerHandler.cpp

@@ -14,6 +14,7 @@
 #include "CGameInfo.h"
 #include "CPlayerInterface.h"
 #include "gui/CGuiHandler.h"
+#include "gui/WindowHandler.h"
 
 #include "lobby/CSelectionBase.h"
 #include "lobby/CLobbyScreen.h"
@@ -325,7 +326,7 @@ void CServerHandler::applyPacksOnLobbyScreen()
 		packsForLobbyScreen.pop_front();
 		CBaseForLobbyApply * apply = applier->getApplier(typeList.getTypeID(pack)); //find the applier
 		apply->applyOnLobbyScreen(static_cast<CLobbyScreen *>(SEL), this, pack);
-		GH.totalRedraw();
+		GH.windows().totalRedraw();
 		delete pack;
 	}
 }
@@ -749,7 +750,7 @@ 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.topInt().get()))
+	while(!settings["session"]["headless"].Bool() && !dynamic_cast<CLobbyScreen *>(GH.windows().topInt().get()))
 		boost::this_thread::sleep(boost::posix_time::milliseconds(50));
 	while(!mi || mapInfo->fileURI != CSH->mi->fileURI)
 	{

+ 5 - 4
client/Client.cpp

@@ -18,6 +18,7 @@
 #include "adventureMap/AdventureMapInterface.h"
 #include "battle/BattleInterface.h"
 #include "gui/CGuiHandler.h"
+#include "gui/WindowHandler.h"
 #include "mapView/mapHandler.h"
 
 #include "../CCallback.h"
@@ -766,11 +767,11 @@ void CClient::removeGUI()
 {
 	// CClient::endGame
 	GH.curInt = nullptr;
-	if(GH.topInt())
-		GH.topInt()->deactivate();
+	if(GH.windows().topInt())
+		GH.windows().topInt()->deactivate();
 	adventureInt.reset();
-	GH.listInt.clear();
-	GH.objsToBlit.clear();
+	GH.windows().listInt.clear();
+	GH.windows().objsToBlit.clear();
 	GH.statusbar.reset();
 	logGlobal->info("Removed GUI.");
 

+ 5 - 4
client/ClientCommandManager.cpp

@@ -16,6 +16,7 @@
 #include "PlayerLocalState.h"
 #include "CServerHandler.h"
 #include "gui/CGuiHandler.h"
+#include "gui/WindowHandler.h"
 #include "../lib/NetPacks.h"
 #include "ClientNetPackVisitors.h"
 #include "../lib/CConfigHandler.h"
@@ -100,7 +101,7 @@ void ClientCommandManager::handleGoSoloCommand()
 				CSH->client->installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), elem.first);
 			}
 		}
-		GH.totalRedraw();
+		GH.windows().totalRedraw();
 		giveTurn(color);
 	}
 	session["aiSolo"].Bool() = !session["aiSolo"].Bool();
@@ -141,7 +142,7 @@ void ClientCommandManager::handleControlaiCommand(std::istringstream& singleWord
 		CSH->client->installNewPlayerInterface(std::make_shared<CPlayerInterface>(elem.first), elem.first);
 	}
 
-	GH.totalRedraw();
+	GH.windows().totalRedraw();
 	if(color != PlayerColor::NEUTRAL)
 		giveTurn(color);
 }
@@ -170,7 +171,7 @@ void ClientCommandManager::handleSetBattleAICommand(std::istringstream& singleWo
 
 void ClientCommandManager::handleRedrawCommand()
 {
-	GH.totalRedraw();
+	GH.windows().totalRedraw();
 }
 
 void ClientCommandManager::handleScreenCommand()
@@ -195,7 +196,7 @@ void ClientCommandManager::handleNotDialogCommand()
 
 void ClientCommandManager::handleGuiCommand()
 {
-	for(const auto & child : GH.listInt)
+	for(const auto & child : GH.windows().listInt)
 	{
 		const auto childPtr = child.get();
 		if(const CIntObject * obj = dynamic_cast<const CIntObject*>(childPtr))

+ 6 - 5
client/NetPacksLobbyClient.cpp

@@ -21,6 +21,7 @@
 #include "CServerHandler.h"
 #include "CGameInfo.h"
 #include "gui/CGuiHandler.h"
+#include "gui/WindowHandler.h"
 #include "widgets/Buttons.h"
 #include "widgets/TextControls.h"
 
@@ -38,7 +39,7 @@ void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyClientConnected(LobbyClientCon
 	{
 		handler.c->connectionID = pack.clientId;
 		if(!settings["session"]["headless"].Bool())
-			GH.pushIntT<CLobbyScreen>(static_cast<ESelectionScreen>(handler.screenType));
+			GH.windows().pushIntT<CLobbyScreen>(static_cast<ESelectionScreen>(handler.screenType));
 		handler.state = EClientState::LOBBY;
 	}
 }
@@ -56,8 +57,8 @@ void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyClientDisconnected(LobbyClient
 
 void ApplyOnLobbyScreenNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
 {
-	if(GH.listInt.size())
-		GH.popInts(1);
+	if(GH.windows().listInt.size())
+		GH.windows().popInts(1);
 }
 
 void ApplyOnLobbyScreenNetPackVisitor::visitLobbyChatMessage(LobbyChatMessage & pack)
@@ -128,7 +129,7 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack
 	if(pack.clientId != -1 && pack.clientId != handler.c->connectionID)
 		return;
 	
-	GH.pushIntT<CLoadingScreen>(std::bind(&CServerHandler::startGameplay, &handler, pack.initializedGameState));
+	GH.windows().pushIntT<CLoadingScreen>(std::bind(&CServerHandler::startGameplay, &handler, pack.initializedGameState));
 }
 
 void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyUpdateState(LobbyUpdateState & pack)
@@ -145,7 +146,7 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyUpdateState(LobbyUpdateState &
 	if(!lobby->bonusSel && handler.si->campState && handler.state == EClientState::LOBBY_CAMPAIGN)
 	{
 		lobby->bonusSel = std::make_shared<CBonusSelection>();
-		GH.pushInt(lobby->bonusSel);
+		GH.windows().pushInt(lobby->bonusSel);
 	}
 
 	if(lobby->bonusSel)

+ 2 - 1
client/adventureMap/AdventureMapInterface.cpp

@@ -27,6 +27,7 @@
 #include "../gui/CursorHandler.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/Shortcut.h"
+#include "../gui/WindowHandler.h"
 #include "../CMT.h"
 #include "../PlayerLocalState.h"
 #include "../CPlayerInterface.h"
@@ -395,7 +396,7 @@ void AdventureMapInterface::onPlayerTurnStarted(PlayerColor playerID)
 
 	if(settings["session"]["autoSkip"].Bool() && !GH.isKeyboardShiftDown())
 	{
-		if(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt().get()))
+		if(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.windows().topInt().get()))
 			iw->close();
 
 		hotkeyEndingTurn();

+ 7 - 6
client/adventureMap/AdventureMapShortcuts.cpp

@@ -16,6 +16,7 @@
 #include "../PlayerLocalState.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/Shortcut.h"
+#include "../gui/WindowHandler.h"
 #include "../lobby/CSavingScreen.h"
 #include "../mapView/mapHandler.h"
 #include "../windows/CKingdomInterface.h"
@@ -96,7 +97,7 @@ std::vector<AdventureMapShortcutState> AdventureMapShortcuts::getShortcuts()
 
 void AdventureMapShortcuts::showOverview()
 {
-	GH.pushIntT<CKingdomInterface>();
+	GH.windows().pushIntT<CKingdomInterface>();
 }
 
 void AdventureMapShortcuts::worldViewBack()
@@ -186,17 +187,17 @@ void AdventureMapShortcuts::showSpellbook()
 
 	owner.centerOnObject(LOCPLINT->localState->getCurrentHero());
 
-	GH.pushIntT<CSpellWindow>(LOCPLINT->localState->getCurrentHero(), LOCPLINT, false);
+	GH.windows().pushIntT<CSpellWindow>(LOCPLINT->localState->getCurrentHero(), LOCPLINT, false);
 }
 
 void AdventureMapShortcuts::adventureOptions()
 {
-	GH.pushIntT<AdventureOptions>();
+	GH.windows().pushIntT<AdventureOptions>();
 }
 
 void AdventureMapShortcuts::systemOptions()
 {
-	GH.pushIntT<SettingsMainWindow>();
+	GH.windows().pushIntT<SettingsMainWindow>();
 }
 
 void AdventureMapShortcuts::nextHero()
@@ -266,7 +267,7 @@ void AdventureMapShortcuts::showScenarioInfo()
 
 void AdventureMapShortcuts::saveGame()
 {
-	GH.pushIntT<CSavingScreen>();
+	GH.windows().pushIntT<CSavingScreen>();
 }
 
 void AdventureMapShortcuts::loadGame()
@@ -326,7 +327,7 @@ void AdventureMapShortcuts::showMarketplace()
 	}
 
 	if(townWithMarket) //if any town has marketplace, open window
-		GH.pushIntT<CMarketplaceWindow>(townWithMarket);
+		GH.windows().pushIntT<CMarketplaceWindow>(townWithMarket);
 	else //if not - complain
 		LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithMarket"));
 }

+ 3 - 2
client/adventureMap/AdventureOptions.cpp

@@ -17,6 +17,7 @@
 #include "../lobby/CCampaignInfoScreen.h"
 #include "../lobby/CScenarioInfoScreen.h"
 #include "../gui/CGuiHandler.h"
+#include "../gui/WindowHandler.h"
 #include "../gui/Shortcut.h"
 #include "../widgets/Buttons.h"
 
@@ -50,11 +51,11 @@ void AdventureOptions::showScenarioInfo()
 {
 	if(LOCPLINT->cb->getStartInfo()->campState)
 	{
-		GH.pushIntT<CCampaignInfoScreen>();
+		GH.windows().pushIntT<CCampaignInfoScreen>();
 	}
 	else
 	{
-		GH.pushIntT<CScenarioInfoScreen>();
+		GH.windows().pushIntT<CScenarioInfoScreen>();
 	}
 }
 

+ 3 - 2
client/adventureMap/CInGameConsole.cpp

@@ -17,6 +17,7 @@
 #include "../PlayerLocalState.h"
 #include "../ClientCommandManager.h"
 #include "../gui/CGuiHandler.h"
+#include "../gui/WindowHandler.h"
 #include "../gui/Shortcut.h"
 #include "../render/Colors.h"
 #include "../adventureMap/AdventureMapInterface.h"
@@ -77,7 +78,7 @@ void CInGameConsole::tick(uint32_t msPassed)
 	}
 
 	if(sizeBefore != texts.size())
-		GH.totalRedraw(); // FIXME: ingame console has no parent widget set
+		GH.windows().totalRedraw(); // FIXME: ingame console has no parent widget set
 }
 
 void CInGameConsole::print(const std::string & txt)
@@ -101,7 +102,7 @@ void CInGameConsole::print(const std::string & txt)
 			texts.erase(texts.begin());
 	}
 
-	GH.totalRedraw(); // FIXME: ingame console has no parent widget set
+	GH.windows().totalRedraw(); // FIXME: ingame console has no parent widget set
 }
 
 void CInGameConsole::keyPressed (EShortcut key)

+ 2 - 1
client/adventureMap/CInfoBar.cpp

@@ -24,6 +24,7 @@
 #include "../CPlayerInterface.h"
 #include "../PlayerLocalState.h"
 #include "../gui/CGuiHandler.h"
+#include "../gui/WindowHandler.h"
 
 #include "../../CCallback.h"
 #include "../../lib/CGeneralTextHandler.h"
@@ -261,7 +262,7 @@ void CInfoBar::tick(uint32_t msPassed)
 	{
 		timerCounter = 0;
 		removeUsedEvents(TIME);
-		if(GH.topInt() == adventureInt)
+		if(GH.windows().topInt() == adventureInt)
 			popComponents(true);
 	}
 	else

+ 2 - 1
client/adventureMap/CMinimap.cpp

@@ -17,6 +17,7 @@
 #include "../CGameInfo.h"
 #include "../CPlayerInterface.h"
 #include "../gui/CGuiHandler.h"
+#include "../gui/WindowHandler.h"
 #include "../render/Colors.h"
 #include "../renderSDL/SDL_Extensions.h"
 #include "../render/Canvas.h"
@@ -131,7 +132,7 @@ void CMinimap::moveAdvMapSelection()
 	adventureInt->centerOnTile(newLocation);
 
 	if (!(adventureInt->active & GENERAL))
-		GH.totalRedraw(); //redraw this as well as inactive adventure map
+		GH.windows().totalRedraw(); //redraw this as well as inactive adventure map
 	else
 		redraw();//redraw only this
 }

+ 3 - 2
client/battle/BattleActionsController.cpp

@@ -22,6 +22,7 @@
 #include "../gui/CursorHandler.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/CIntObject.h"
+#include "../gui/WindowHandler.h"
 #include "../windows/CCreatureWindow.h"
 
 #include "../../CCallback.h"
@@ -668,7 +669,7 @@ void BattleActionsController::actionRealize(PossiblePlayerBattleAction action, B
 
 		case PossiblePlayerBattleAction::CREATURE_INFO:
 		{
-			GH.pushIntT<CStackWindow>(targetStack, false);
+			GH.windows().pushIntT<CStackWindow>(targetStack, false);
 			return;
 		}
 
@@ -973,7 +974,7 @@ void BattleActionsController::onHexRightClicked(BattleHex clickedHex)
 	auto selectedStack = owner.curInt->cb->battleGetStackByPos(clickedHex, true);
 
 	if (selectedStack != nullptr)
-		GH.pushIntT<CStackWindow>(selectedStack, true);
+		GH.windows().pushIntT<CStackWindow>(selectedStack, true);
 
 	if (clickedHex == BattleHex::HERO_ATTACKER && owner.attackingHero)
 		owner.attackingHero->heroRightClicked();

+ 4 - 3
client/battle/BattleInterface.cpp

@@ -28,6 +28,7 @@
 #include "../CPlayerInterface.h"
 #include "../gui/CursorHandler.h"
 #include "../gui/CGuiHandler.h"
+#include "../gui/WindowHandler.h"
 #include "../render/Canvas.h"
 #include "../adventureMap/AdventureMapInterface.h"
 
@@ -95,7 +96,7 @@ BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet *
 	adventureInt->onAudioPaused();
 	ongoingAnimationsState.set(true);
 
-	GH.pushInt(windowObject);
+	GH.windows().pushInt(windowObject);
 	windowObject->blockUI(true);
 	windowObject->updateQueue();
 
@@ -167,7 +168,7 @@ BattleInterface::~BattleInterface()
 void BattleInterface::redrawBattlefield()
 {
 	fieldController->redrawBackgroundWithHexes();
-	GH.totalRedraw();
+	GH.windows().totalRedraw();
 }
 
 void BattleInterface::stackReset(const CStack * stack)
@@ -328,7 +329,7 @@ void BattleInterface::battleFinished(const BattleResult& br, QueryID queryID)
 	{
 		curInt->cb->selectionMade(selection, queryID);
 	};
-	GH.pushInt(wnd);
+	GH.windows().pushInt(wnd);
 	
 	curInt->waitWhileDialog(); // Avoid freeze when AI end turn after battle. Check bug #1897
 	CPlayerInterface::battleInt = nullptr;

+ 5 - 4
client/battle/BattleInterfaceClasses.cpp

@@ -25,6 +25,7 @@
 #include "../gui/CursorHandler.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/Shortcut.h"
+#include "../gui/WindowHandler.h"
 #include "../render/Canvas.h"
 #include "../render/IImage.h"
 #include "../widgets/Buttons.h"
@@ -289,7 +290,7 @@ void BattleHero::heroLeftClicked()
 	if(owner.getCurrentPlayerInterface()->cb->battleCanCastSpell(hero, spells::Mode::HERO) == ESpellCastProblem::OK) //check conditions
 	{
 		CCS->curh->set(Cursor::Map::POINTER);
-		GH.pushIntT<CSpellWindow>(hero, owner.getCurrentPlayerInterface());
+		GH.windows().pushIntT<CSpellWindow>(hero, owner.getCurrentPlayerInterface());
 	}
 }
 
@@ -304,7 +305,7 @@ void BattleHero::heroRightClicked()
 	{
 		auto h = defender ? owner.defendingHeroInstance : owner.attackingHeroInstance;
 		targetHero.initFromHero(h, InfoAboutHero::EInfoLevel::INBATTLE);
-		GH.pushIntT<HeroInfoWindow>(targetHero, &windowPosition);
+		GH.windows().pushIntT<HeroInfoWindow>(targetHero, &windowPosition);
 	}
 }
 
@@ -591,8 +592,8 @@ void BattleResultWindow::buttonPressed(int button)
 
 	close();
 
-	if(dynamic_cast<BattleWindow*>(GH.topInt().get()))
-		GH.popInts(1); //pop battle interface if present
+	if(dynamic_cast<BattleWindow*>(GH.windows().topInt().get()))
+		GH.windows().popInts(1); //pop battle interface if present
 
 	//Result window and battle interface are gone. We requested all dialogs to be closed before opening the battle,
 	//so we can be sure that there is no dialogs left on GUI stack.

+ 7 - 6
client/battle/BattleWindow.cpp

@@ -22,6 +22,7 @@
 #include "../gui/CursorHandler.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/Shortcut.h"
+#include "../gui/WindowHandler.h"
 #include "../windows/CSpellWindow.h"
 #include "../widgets/Buttons.h"
 #include "../widgets/Images.h"
@@ -152,7 +153,7 @@ void BattleWindow::hideQueue()
 		pos.h -= queue->pos.h;
 		pos = center();
 	}
-	GH.totalRedraw();
+	GH.windows().totalRedraw();
 }
 
 void BattleWindow::showQueue()
@@ -165,7 +166,7 @@ void BattleWindow::showQueue()
 
 	createQueue();
 	updateQueue();
-	GH.totalRedraw();
+	GH.windows().totalRedraw();
 }
 
 void BattleWindow::updateQueue()
@@ -256,7 +257,7 @@ void BattleWindow::bOptionsf()
 
 	CCS->curh->set(Cursor::Map::POINTER);
 
-	GH.pushIntT<SettingsMainWindow>(&owner);
+	GH.windows().pushIntT<SettingsMainWindow>(&owner);
 }
 
 void BattleWindow::bSurrenderf()
@@ -424,7 +425,7 @@ void BattleWindow::bSpellf()
 
 	if(spellCastProblem == ESpellCastProblem::OK)
 	{
-		GH.pushIntT<CSpellWindow>(myHero, owner.curInt.get());
+		GH.windows().pushIntT<CSpellWindow>(myHero, owner.curInt.get());
 	}
 	else if (spellCastProblem == ESpellCastProblem::MAGIC_IS_BLOCKED)
 	{
@@ -569,7 +570,7 @@ void BattleWindow::show(SDL_Surface *to)
 
 void BattleWindow::close()
 {
-	if(GH.topInt().get() != this)
+	if(GH.windows().topInt().get() != this)
 		logGlobal->error("Only top interface must be closed");
-	GH.popInts(1);
+	GH.windows().popInts(1);
 }

+ 13 - 88
client/gui/CGuiHandler.cpp

@@ -15,6 +15,7 @@
 #include "CursorHandler.h"
 #include "ShortcutHandler.h"
 #include "FramerateManager.h"
+#include "WindowHandler.h"
 
 #include "../CGameInfo.h"
 #include "../render/Colors.h"
@@ -99,6 +100,7 @@ void CGuiHandler::processLists(const ui16 activityFlag, std::function<void (std:
 
 void CGuiHandler::init()
 {
+	windowHandlerInstance = std::make_unique<WindowHandler>();
 	screenHandlerInstance = std::make_unique<ScreenHandler>();
 	shortcutsHandlerInstance = std::make_unique<ShortcutHandler>();
 	framerateManagerInstance = std::make_unique<FramerateManager>(settings["video"]["targetfps"].Integer());
@@ -125,73 +127,6 @@ void CGuiHandler::handleElementDeActivate(CIntObject * elem, ui16 activityFlag)
 	elem->active_m &= ~activityFlag;
 }
 
-void CGuiHandler::popInt(std::shared_ptr<IShowActivatable> top)
-{
-	assert(listInt.front() == top);
-	top->deactivate();
-	disposed.push_back(top);
-	listInt.pop_front();
-	objsToBlit -= top;
-	if(!listInt.empty())
-		listInt.front()->activate();
-	totalRedraw();
-}
-
-void CGuiHandler::pushInt(std::shared_ptr<IShowActivatable> newInt)
-{
-	assert(newInt);
-	assert(!vstd::contains(listInt, newInt)); // do not add same object twice
-
-	//a new interface will be present, we'll need to use buffer surface (unless it's advmapint that will alter screenBuf on activate anyway)
-	screenBuf = screen2;
-
-	if(!listInt.empty())
-		listInt.front()->deactivate();
-	listInt.push_front(newInt);
-	CCS->curh->set(Cursor::Map::POINTER);
-	newInt->activate();
-	objsToBlit.push_back(newInt);
-	totalRedraw();
-}
-
-void CGuiHandler::popInts(int howMany)
-{
-	if(!howMany) return; //senseless but who knows...
-
-	assert(listInt.size() >= howMany);
-	listInt.front()->deactivate();
-	for(int i=0; i < howMany; i++)
-	{
-		objsToBlit -= listInt.front();
-		disposed.push_back(listInt.front());
-		listInt.pop_front();
-	}
-
-	if(!listInt.empty())
-	{
-		listInt.front()->activate();
-		totalRedraw();
-	}
-	fakeMouseMove();
-}
-
-std::shared_ptr<IShowActivatable> CGuiHandler::topInt()
-{
-	if(listInt.empty())
-		return std::shared_ptr<IShowActivatable>();
-	else
-		return listInt.front();
-}
-
-void CGuiHandler::totalRedraw()
-{
-	CSDL_Ext::fillSurface( screen2, Colors::BLACK);
-
-	for(auto & elem : objsToBlit)
-		elem->showAll(screen2);
-	CSDL_Ext::blitAt(screen2,0,0,screen);
-}
-
 void CGuiHandler::updateTime()
 {
 	int ms = framerateManager().getElapsedMilliseconds();
@@ -397,7 +332,7 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
 				//not working yet since CClient::run remain locked after BattleInterface removal
 //				if(LOCPLINT->battleInt)
 //				{
-//					GH.popInts(1);
+//					GH.windows().popInts(1);
 //					vstd::clear_pointer(LOCPLINT->battleInt);
 //				}
 				break;
@@ -635,15 +570,6 @@ void CGuiHandler::handleMouseMotion(const SDL_Event & current)
 		handleMoveInterested(current.motion);
 }
 
-void CGuiHandler::simpleRedraw()
-{
-	//update only top interface and draw background
-	if(objsToBlit.size() > 1)
-		CSDL_Ext::blitAt(screen2,0,0,screen); //blit background
-	if(!objsToBlit.empty())
-		objsToBlit.back()->show(screen); //blit active interface/window
-}
-
 void CGuiHandler::handleMoveInterested(const SDL_MouseMotionEvent & motion)
 {
 	//sending active, MotionInterested objects mouseMoved() call
@@ -690,7 +616,7 @@ void CGuiHandler::renderFrame()
 
 		SDL_RenderPresent(mainRenderer);
 
-		disposed.clear();
+		windows().onFrameRendered();
 	}
 
 	framerateManager().framerateDelay(); // holds a constant FPS
@@ -706,8 +632,8 @@ CGuiHandler::CGuiHandler()
 	, continueEventHandling(true)
 	, curInt(nullptr)
 	, statusbar(nullptr)
+	, terminate_cond (new CondSh<bool>(false))
 {
-	terminate_cond = new CondSh<bool>(false);
 }
 
 CGuiHandler::~CGuiHandler()
@@ -816,15 +742,14 @@ IScreenHandler & CGuiHandler::screenHandler()
 	return *screenHandlerInstance;
 }
 
-void CGuiHandler::onScreenResize()
+WindowHandler & CGuiHandler::windows()
 {
-	for (auto const & entry : listInt)
-	{
-		auto intObject = std::dynamic_pointer_cast<CIntObject>(entry);
-
-		if (intObject)
-			intObject->onScreenResize();
-	}
+	assert(windowHandlerInstance);
+	return *windowHandlerInstance;
+}
 
-	totalRedraw();
+void CGuiHandler::onScreenResize()
+{
+	screenHandler().onScreenResize();
+	windows().onScreenResize();
 }

+ 4 - 22
client/gui/CGuiHandler.h

@@ -30,6 +30,7 @@ class IUpdateable;
 class IShowActivatable;
 class IShowable;
 class IScreenHandler;
+class WindowHandler;
 
 // TODO: event handling need refactoring
 enum class EUserEvent
@@ -49,16 +50,14 @@ class CGuiHandler
 {
 public:
 
-	std::list<std::shared_ptr<IShowActivatable>> listInt; //list of interfaces - front=foreground; back = background (includes adventure map, window interfaces, all kind of active dialogs, and so on)
 	std::shared_ptr<IStatusBar> statusbar;
 
 private:
 	Point cursorPosition;
 	uint32_t mouseButtonsMask;
 
-	std::vector<std::shared_ptr<IShowActivatable>> disposed;
-
 	std::unique_ptr<ShortcutHandler> shortcutsHandlerInstance;
+	std::unique_ptr<WindowHandler> windowHandlerInstance;
 
 	std::atomic<bool> continueEventHandling;
 	using CIntObjectList = std::list<CIntObject *>;
@@ -91,8 +90,6 @@ public:
 	void handleElementActivate(CIntObject * elem, ui16 activityFlag);
 	void handleElementDeActivate(CIntObject * elem, ui16 activityFlag);
 public:
-	//objs to blit
-	std::vector<std::shared_ptr<IShowActivatable>> objsToBlit;
 
 	/// returns current position of mouse cursor, relative to vcmi window
 	const Point & getCursorPosition() const;
@@ -123,6 +120,8 @@ public:
 
 	IScreenHandler & screenHandler();
 
+	WindowHandler & windows();
+
 	IUpdateable *curInt;
 
 	Point lastClick;
@@ -141,26 +140,9 @@ public:
 	void init();
 	void renderFrame();
 
-	void totalRedraw(); //forces total redraw (using showAll), sets a flag, method gets called at the end of the rendering
-	void simpleRedraw(); //update only top interface and draw background from buffer, sets a flag, method gets called at the end of the rendering
-
 	/// called whenever user selects different resolution, requiring to center/resize all windows
 	void onScreenResize();
 
-	void pushInt(std::shared_ptr<IShowActivatable> newInt); //deactivate old top interface, activates this one and pushes to the top
-	template <typename T, typename ... Args>
-	void pushIntT(Args && ... args)
-	{
-		auto newInt = std::make_shared<T>(std::forward<Args>(args)...);
-		pushInt(newInt);
-	}
-
-	void popInts(int howMany); //pops one or more interfaces - deactivates top, deletes and removes given number of interfaces, activates new front
-
-	void popInt(std::shared_ptr<IShowActivatable> top); //removes given interface from the top and activates next
-
-	std::shared_ptr<IShowActivatable> topInt(); //returns top interface
-
 	void updateTime(); //handles timeInterested
 	void handleEvents(); //takes events from queue and calls interested objects
 	void fakeMouseMove();

+ 3 - 2
client/gui/CIntObject.cpp

@@ -11,6 +11,7 @@
 #include "CIntObject.h"
 
 #include "CGuiHandler.h"
+#include "WindowHandler.h"
 #include "Shortcut.h"
 #include "../renderSDL/SDL_Extensions.h"
 #include "../windows/CMessage.h"
@@ -356,9 +357,9 @@ WindowBase::WindowBase(int used_, Point pos_)
 
 void WindowBase::close()
 {
-	if(GH.topInt().get() != this)
+	if(GH.windows().topInt().get() != this)
 		logGlobal->error("Only top interface must be closed");
-	GH.popInts(1);
+	GH.windows().popInts(1);
 }
 
 IStatusBar::~IStatusBar()

+ 115 - 0
client/gui/WindowHandler.cpp

@@ -0,0 +1,115 @@
+/*
+ * WindowHandler.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+#include "WindowHandler.h"
+
+#include "CGuiHandler.h"
+#include "CIntObject.h"
+#include "CursorHandler.h"
+
+#include "../CMT.h"
+#include "../CGameInfo.h"
+#include "../render/Colors.h"
+#include "../renderSDL/SDL_Extensions.h"
+
+void WindowHandler::popInt(std::shared_ptr<IShowActivatable> top)
+{
+	assert(listInt.front() == top);
+	top->deactivate();
+	disposed.push_back(top);
+	listInt.pop_front();
+	objsToBlit -= top;
+	if(!listInt.empty())
+		listInt.front()->activate();
+	totalRedraw();
+}
+
+void WindowHandler::pushInt(std::shared_ptr<IShowActivatable> newInt)
+{
+	assert(newInt);
+	assert(!vstd::contains(listInt, newInt)); // do not add same object twice
+
+	//a new interface will be present, we'll need to use buffer surface (unless it's advmapint that will alter screenBuf on activate anyway)
+	screenBuf = screen2;
+
+	if(!listInt.empty())
+		listInt.front()->deactivate();
+	listInt.push_front(newInt);
+	CCS->curh->set(Cursor::Map::POINTER);
+	newInt->activate();
+	objsToBlit.push_back(newInt);
+	totalRedraw();
+}
+
+void WindowHandler::popInts(int howMany)
+{
+	if(!howMany)
+		return; //senseless but who knows...
+
+	assert(listInt.size() >= howMany);
+	listInt.front()->deactivate();
+	for(int i = 0; i < howMany; i++)
+	{
+		objsToBlit -= listInt.front();
+		disposed.push_back(listInt.front());
+		listInt.pop_front();
+	}
+
+	if(!listInt.empty())
+	{
+		listInt.front()->activate();
+		totalRedraw();
+	}
+	GH.fakeMouseMove();
+}
+
+std::shared_ptr<IShowActivatable> WindowHandler::topInt()
+{
+	if(listInt.empty())
+		return std::shared_ptr<IShowActivatable>();
+	else
+		return listInt.front();
+}
+
+void WindowHandler::totalRedraw()
+{
+	CSDL_Ext::fillSurface(screen2, Colors::BLACK);
+
+	for(auto & elem : objsToBlit)
+		elem->showAll(screen2);
+	CSDL_Ext::blitAt(screen2, 0, 0, screen);
+}
+
+void WindowHandler::simpleRedraw()
+{
+	//update only top interface and draw background
+	if(objsToBlit.size() > 1)
+		CSDL_Ext::blitAt(screen2, 0, 0, screen); //blit background
+	if(!objsToBlit.empty())
+		objsToBlit.back()->show(screen); //blit active interface/window
+}
+
+void WindowHandler::onScreenResize()
+{
+	for(const auto & entry : listInt)
+	{
+		auto intObject = std::dynamic_pointer_cast<CIntObject>(entry);
+
+		if(intObject)
+			intObject->onScreenResize();
+	}
+
+	totalRedraw();
+}
+
+void WindowHandler::onFrameRendered()
+{
+	disposed.clear();
+}

+ 54 - 0
client/gui/WindowHandler.h

@@ -0,0 +1,54 @@
+/*
+ * WindowHandler.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+class IShowActivatable;
+
+class WindowHandler
+{
+public:
+	/// list of interfaces - front=foreground; back = background (includes adventure map, window interfaces, all kind of active dialogs, and so on)
+	std::list<std::shared_ptr<IShowActivatable>> listInt;
+
+	std::vector<std::shared_ptr<IShowActivatable>> disposed;
+
+	// objs to blit
+	std::vector<std::shared_ptr<IShowActivatable>> objsToBlit;
+
+	/// forces total redraw (using showAll), sets a flag, method gets called at the end of the rendering
+	void totalRedraw();
+
+	/// update only top interface and draw background from buffer, sets a flag, method gets called at the end of the rendering
+	void simpleRedraw();
+
+	/// called whenever user selects different resolution, requiring to center/resize all windows
+	void onScreenResize();
+
+	/// deactivate old top interface, activates this one and pushes to the top
+	void pushInt(std::shared_ptr<IShowActivatable> newInt);
+	template <typename T, typename ... Args>
+	void pushIntT(Args && ... args)
+	{
+		auto newInt = std::make_shared<T>(std::forward<Args>(args)...);
+		pushInt(newInt);
+	}
+
+	/// pops one or more interfaces - deactivates top, deletes and removes given number of interfaces, activates new front
+	void popInts(int howMany);
+
+	/// removes given interface from the top and activates next
+	void popInt(std::shared_ptr<IShowActivatable> top);
+
+	/// returns top interface
+	std::shared_ptr<IShowActivatable> topInt();
+
+
+	void onFrameRendered();
+};

+ 3 - 2
client/lobby/CBonusSelection.cpp

@@ -34,6 +34,7 @@
 #include "../render/CAnimation.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/Shortcut.h"
+#include "../gui/WindowHandler.h"
 
 #include "../../lib/filesystem/Filesystem.h"
 #include "../../lib/CGeneralTextHandler.h"
@@ -367,7 +368,7 @@ void CBonusSelection::goBack()
 {
 	if(CSH->state != EClientState::GAMEPLAY)
 	{
-		GH.popInts(2);
+		GH.windows().popInts(2);
 	}
 	else
 	{
@@ -397,7 +398,7 @@ void CBonusSelection::startMap()
 		const CCampaignScenario & scenario = getCampaign()->camp->scenarios[CSH->campaignMap];
 		if(scenario.prolog.hasPrologEpilog)
 		{
-			GH.pushIntT<CPrologEpilogVideo>(scenario.prolog, exitCb);
+			GH.windows().pushIntT<CPrologEpilogVideo>(scenario.prolog, exitCb);
 		}
 		else
 		{

+ 4 - 3
client/lobby/CSelectionBase.cpp

@@ -26,6 +26,7 @@
 #include "../CServerHandler.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/Shortcut.h"
+#include "../gui/WindowHandler.h"
 #include "../mainmenu/CMainMenu.h"
 #include "../widgets/CComponent.h"
 #include "../widgets/Buttons.h"
@@ -105,7 +106,7 @@ void CSelectionBase::toggleTab(std::shared_ptr<CIntObject> tab)
 	{
 		curTab.reset();
 	}
-	GH.totalRedraw();
+	GH.windows().totalRedraw();
 }
 
 InfoCard::InfoCard()
@@ -299,7 +300,7 @@ void InfoCard::setChat(bool activateChat)
 	}
 
 	showChat = activateChat;
-	GH.totalRedraw();
+	GH.windows().totalRedraw();
 }
 
 CChatBox::CChatBox(const Rect & rect)
@@ -378,7 +379,7 @@ void CFlagBox::recreate()
 void CFlagBox::clickRight(tribool down, bool previousState)
 {
 	if(down && SEL->getMapInfo())
-		GH.pushIntT<CFlagBoxTooltipBox>(iconsTeamFlags);
+		GH.windows().pushIntT<CFlagBoxTooltipBox>(iconsTeamFlags);
 }
 
 CFlagBox::CFlagBoxTooltipBox::CFlagBoxTooltipBox(std::shared_ptr<CAnimation> icons)

+ 2 - 1
client/lobby/OptionsTab.cpp

@@ -15,6 +15,7 @@
 #include "../CGameInfo.h"
 #include "../CServerHandler.h"
 #include "../gui/CGuiHandler.h"
+#include "../gui/WindowHandler.h"
 #include "../widgets/CComponent.h"
 #include "../widgets/Buttons.h"
 #include "../widgets/MiscWidgets.h"
@@ -435,7 +436,7 @@ void OptionsTab::SelectedBox::clickRight(tribool down, bool previousState)
 		if(settings.hero == -2 && !SEL->getPlayerInfo(settings.color.getNum()).hasCustomMainHero() && CPlayerSettingsHelper::type == HERO)
 			return;
 
-		GH.pushIntT<CPlayerOptionTooltipBox>(*this);
+		GH.windows().pushIntT<CPlayerOptionTooltipBox>(*this);
 	}
 }
 

+ 11 - 10
client/lobby/RandomMapTab.cpp

@@ -15,6 +15,7 @@
 #include "../CGameInfo.h"
 #include "../CServerHandler.h"
 #include "../gui/CGuiHandler.h"
+#include "../gui/WindowHandler.h"
 #include "../widgets/CComponent.h"
 #include "../widgets/Buttons.h"
 #include "../widgets/MiscWidgets.h"
@@ -102,12 +103,12 @@ RandomMapTab::RandomMapTab():
 	//new callbacks available only from mod
 	addCallback("templateSelection", [&](int)
 	{
-		GH.pushIntT<TemplatesDropBox>(*this, int3{mapGenOptions->getWidth(), mapGenOptions->getHeight(), 1 + mapGenOptions->getHasTwoLevels()});
+		GH.windows().pushIntT<TemplatesDropBox>(*this, int3{mapGenOptions->getWidth(), mapGenOptions->getHeight(), 1 + mapGenOptions->getHasTwoLevels()});
 	});
 	
 	addCallback("teamAlignments", [&](int)
 	{
-		GH.pushIntT<TeamAlignmentsWidget>(*this);
+		GH.windows().pushIntT<TeamAlignmentsWidget>(*this);
 	});
 	
 	for(auto road : VLC->roadTypeHandler->objects)
@@ -482,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.topInt().get() == this);
-			GH.popInt(GH.topInt());
+			assert(GH.windows().topInt().get() == this);
+			GH.windows().popInt(GH.windows().topInt());
 		}
 	}
 }
@@ -511,8 +512,8 @@ void TemplatesDropBox::updateListItems()
 void TemplatesDropBox::setTemplate(const CRmgTemplate * tmpl)
 {
 	randomMapTab.setTemplate(tmpl);
-	assert(GH.topInt().get() == this);
-	GH.popInt(GH.topInt());
+	assert(GH.windows().topInt().get() == this);
+	GH.windows().popInt(GH.windows().topInt());
 }
 
 TeamAlignmentsWidget::TeamAlignmentsWidget(RandomMapTab & randomMapTab):
@@ -547,14 +548,14 @@ TeamAlignmentsWidget::TeamAlignmentsWidget(RandomMapTab & randomMapTab):
 			randomMapTab.obtainMapGenOptions().setPlayerTeam(PlayerColor(plId), TeamID(players[plId]->getSelected()));
 		}
 		randomMapTab.updateMapInfoByHost();
-		assert(GH.topInt().get() == this);
-		GH.popInt(GH.topInt());
+		assert(GH.windows().topInt().get() == this);
+		GH.windows().popInt(GH.windows().topInt());
 	});
 	
 	addCallback("cancel", [&](int)
 	{
-		assert(GH.topInt().get() == this);
-		GH.popInt(GH.topInt());
+		assert(GH.windows().topInt().get() == this);
+		GH.windows().popInt(GH.windows().topInt());
 	});
 	
 	build(config);

+ 16 - 15
client/mainmenu/CMainMenu.cpp

@@ -21,6 +21,7 @@
 #include "../gui/CGuiHandler.h"
 #include "../gui/ShortcutHandler.h"
 #include "../gui/Shortcut.h"
+#include "../gui/WindowHandler.h"
 #include "../widgets/CComponent.h"
 #include "../widgets/Buttons.h"
 #include "../widgets/MiscWidgets.h"
@@ -177,7 +178,7 @@ static std::function<void()> genCommand(CMenuScreen * menu, std::vector<std::str
 				case 0:
 					return std::bind(CMainMenu::openLobby, ESelectionScreen::newGame, true, nullptr, ELoadMode::NONE);
 				case 1:
-					return []() { GH.pushIntT<CMultiMode>(ESelectionScreen::newGame); };
+					return []() { GH.windows().pushIntT<CMultiMode>(ESelectionScreen::newGame); };
 				case 2:
 					return std::bind(CMainMenu::openLobby, ESelectionScreen::campaignList, true, nullptr, ELoadMode::NONE);
 				case 3:
@@ -192,7 +193,7 @@ static std::function<void()> genCommand(CMenuScreen * menu, std::vector<std::str
 				case 0:
 					return std::bind(CMainMenu::openLobby, ESelectionScreen::loadGame, true, nullptr, ELoadMode::SINGLE);
 				case 1:
-					return []() { GH.pushIntT<CMultiMode>(ESelectionScreen::loadGame); };
+					return []() { GH.windows().pushIntT<CMultiMode>(ESelectionScreen::loadGame); };
 				case 2:
 					return std::bind(CMainMenu::openLobby, ESelectionScreen::loadGame, true, nullptr, ELoadMode::CAMPAIGN);
 				case 3:
@@ -324,10 +325,10 @@ void CMainMenu::update()
 	if(CMM != this->shared_from_this()) //don't update if you are not a main interface
 		return;
 
-	if(GH.listInt.empty())
+	if(GH.windows().listInt.empty())
 	{
-		GH.pushInt(CMM);
-		GH.pushInt(menu);
+		GH.windows().pushInt(CMM);
+		GH.windows().pushInt(menu);
 		menu->switchToTab(menu->getActiveTab());
 	}
 
@@ -336,9 +337,9 @@ void CMainMenu::update()
 	GH.handleEvents();
 
 	// check for null othervice crash on finishing a campaign
-	// /FIXME: find out why GH.listInt is empty to begin with
-	if(GH.topInt())
-		GH.topInt()->show(screen);
+	// /FIXME: find out why GH.windows().listInt is empty to begin with
+	if(GH.windows().topInt())
+		GH.windows().topInt()->show(screen);
 }
 
 void CMainMenu::openLobby(ESelectionScreen screenType, bool host, const std::vector<std::string> * names, ELoadMode loadMode)
@@ -347,7 +348,7 @@ void CMainMenu::openLobby(ESelectionScreen screenType, bool host, const std::vec
 	CSH->screenType = screenType;
 	CSH->loadMode = loadMode;
 
-	GH.pushIntT<CSimpleJoinScreen>(host);
+	GH.windows().pushIntT<CSimpleJoinScreen>(host);
 }
 
 void CMainMenu::openCampaignLobby(const std::string & campaignFileName)
@@ -361,14 +362,14 @@ void CMainMenu::openCampaignLobby(std::shared_ptr<CCampaignState> campaign)
 	CSH->resetStateForLobby(StartInfo::CAMPAIGN);
 	CSH->screenType = ESelectionScreen::campaignList;
 	CSH->campaignStateToSend = campaign;
-	GH.pushIntT<CSimpleJoinScreen>();
+	GH.windows().pushIntT<CSimpleJoinScreen>();
 }
 
 void CMainMenu::openCampaignScreen(std::string name)
 {
 	if(vstd::contains(CMainMenuConfig::get().getCampaigns().Struct(), name))
 	{
-		GH.pushIntT<CCampaignScreen>(CMainMenuConfig::get().getCampaigns()[name]);
+		GH.windows().pushIntT<CCampaignScreen>(CMainMenuConfig::get().getCampaigns()[name]);
 		return;
 	}
 	logGlobal->error("Unknown campaign set: %s", name);
@@ -413,14 +414,14 @@ void CMultiMode::hostTCP()
 {
 	auto savedScreenType = screenType;
 	close();
-	GH.pushIntT<CMultiPlayers>(settings["general"]["playerName"].String(), savedScreenType, true, ELoadMode::MULTI);
+	GH.windows().pushIntT<CMultiPlayers>(settings["general"]["playerName"].String(), savedScreenType, true, ELoadMode::MULTI);
 }
 
 void CMultiMode::joinTCP()
 {
 	auto savedScreenType = screenType;
 	close();
-	GH.pushIntT<CMultiPlayers>(settings["general"]["playerName"].String(), savedScreenType, false, ELoadMode::MULTI);
+	GH.windows().pushIntT<CMultiPlayers>(settings["general"]["playerName"].String(), savedScreenType, false, ELoadMode::MULTI);
 }
 
 void CMultiMode::onNameChange(std::string newText)
@@ -522,7 +523,7 @@ void CSimpleJoinScreen::leaveScreen()
 		textTitle->setText("Closing...");
 		CSH->state = EClientState::CONNECTION_CANCELLED;
 	}
-	else if(GH.listInt.size() && GH.listInt.front().get() == this)
+	else if(GH.windows().listInt.size() && GH.windows().listInt.front().get() == this)
 	{
 		close();
 	}
@@ -552,7 +553,7 @@ void CSimpleJoinScreen::connectThread(const std::string & addr, ui16 port)
 	else
 		CSH->justConnectToServer(addr, port);
 
-	if(GH.listInt.size() && GH.listInt.front().get() == this)
+	if(GH.windows().listInt.size() && GH.windows().listInt.front().get() == this)
 	{
 		close();
 	}

+ 3 - 2
client/mapView/MapViewController.cpp

@@ -19,6 +19,7 @@
 #include "../CPlayerInterface.h"
 #include "../adventureMap/AdventureMapInterface.h"
 #include "../gui/CGuiHandler.h"
+#include "../gui/WindowHandler.h"
 
 #include "../../lib/CConfigHandler.h"
 #include "../../lib/CPathfinder.h"
@@ -208,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.topInt() != adventureInt)
+	if(GH.windows().topInt() != adventureInt)
 		return false;
 
 	if(obj->isVisitable())
@@ -225,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.topInt() != adventureInt)
+	if(GH.windows().topInt() != adventureInt)
 		return false;
 
 	if(context->isVisible(obj->convertToVisitablePos(from)))

+ 2 - 1
client/renderSDL/ScreenHandler.cpp

@@ -14,6 +14,7 @@
 #include "../../lib/CConfigHandler.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/NotificationHandler.h"
+#include "../gui/WindowHandler.h"
 #include "CMT.h"
 #include "SDL_Extensions.h"
 
@@ -270,7 +271,7 @@ void ScreenHandler::initializeScreenBuffers()
 		throw std::runtime_error("Unable to copy surface\n");
 	}
 
-	if (GH.listInt.size() > 1)
+	if (GH.windows().listInt.size() > 1)
 		screenBuf = screen2;
 	else
 		screenBuf = screen;

+ 5 - 4
client/widgets/CGarrisonInt.cpp

@@ -14,6 +14,7 @@
 #include "TextControls.h"
 
 #include "../gui/CGuiHandler.h"
+#include "../gui/WindowHandler.h"
 #include "../renderSDL/SDL_Extensions.h"
 #include "../windows/CCreatureWindow.h"
 #include "../windows/GUIClasses.h"
@@ -174,7 +175,7 @@ bool CGarrisonSlot::viewInfo()
 		elem->block(true);
 
 	redraw();
-	GH.pushIntT<CStackWindow>(myStack, dism, pom, upgr);
+	GH.windows().pushIntT<CStackWindow>(myStack, dism, pom, upgr);
 	return true;
 }
 
@@ -183,7 +184,7 @@ bool CGarrisonSlot::viewInfo()
 bool CGarrisonSlot::highlightOrDropArtifact()
 {
 	bool artSelected = false;
-	if (CWindowWithArtifacts* chw = dynamic_cast<CWindowWithArtifacts*>(GH.topInt().get())) //dirty solution
+	if (CWindowWithArtifacts* chw = dynamic_cast<CWindowWithArtifacts*>(GH.windows().topInt().get())) //dirty solution
 	{
 		const auto pickedArtInst = chw->getPickedArtifact();
 
@@ -252,7 +253,7 @@ bool CGarrisonSlot::split()
 	int countLeft = selection->myStack ? selection->myStack->count : 0;
 	int countRight = myStack ? myStack->count : 0;
 
-	GH.pushIntT<CSplitWindow>(selection->creature, std::bind(&CGarrisonInt::splitStacks, owner, _1, _2),
+	GH.windows().pushIntT<CSplitWindow>(selection->creature, std::bind(&CGarrisonInt::splitStacks, owner, _1, _2),
 		minLeft, minRight, countLeft, countRight);
 	return true;
 }
@@ -289,7 +290,7 @@ void CGarrisonSlot::clickRight(tribool down, bool previousState)
 {
 	if(creature && down)
 	{
-		GH.pushIntT<CStackWindow>(myStack, true);
+		GH.windows().pushIntT<CStackWindow>(myStack, true);
 	}
 }
 

+ 3 - 2
client/widgets/CWindowWithArtifacts.cpp

@@ -12,6 +12,7 @@
 
 #include "../gui/CGuiHandler.h"
 #include "../gui/CursorHandler.h"
+#include "../gui/WindowHandler.h"
 
 #include "CComponent.h"
 
@@ -65,7 +66,7 @@ void CWindowWithArtifacts::leftClickArtPlaceHero(CArtifactsOfHeroBase & artsInst
 	{
 		if(artPlace.getArt()->getTypeId() == ArtifactID::SPELLBOOK)
 		{
-			GH.pushIntT<CSpellWindow>(hero, LOCPLINT, LOCPLINT->battleInt.get());
+			GH.windows().pushIntT<CSpellWindow>(hero, LOCPLINT, LOCPLINT->battleInt.get());
 			return false;
 		}
 		if(artPlace.getArt()->getTypeId() == ArtifactID::CATAPULT)
@@ -359,4 +360,4 @@ std::optional<CWindowWithArtifacts::CArtifactsOfHeroPtr> CWindowWithArtifacts::f
 			return res;
 	}
 	return res;
-}
+}

+ 22 - 21
client/windows/CCastleInterface.cpp

@@ -22,6 +22,7 @@
 #include "../PlayerLocalState.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/Shortcut.h"
+#include "../gui/WindowHandler.h"
 #include "../widgets/MiscWidgets.h"
 #include "../widgets/CComponent.h"
 #include "../widgets/Buttons.h"
@@ -158,7 +159,7 @@ void CBuildingRect::clickRight(tribool down, bool previousState)
 		else
 		{
 			int level = ( bid - BuildingID::DWELL_FIRST ) % GameConstants::CREATURES_PER_TOWN;
-			GH.pushIntT<CDwellingInfoBox>(parent->pos.x+parent->pos.w / 2, parent->pos.y+parent->pos.h  /2, town, level);
+			GH.windows().pushIntT<CDwellingInfoBox>(parent->pos.x+parent->pos.w / 2, parent->pos.y+parent->pos.h  /2, town, level);
 		}
 	}
 }
@@ -420,7 +421,7 @@ void CHeroGSlot::clickRight(tribool down, bool previousState)
 {
 	if(hero && down)
 	{
-		GH.pushIntT<CInfoBoxPopup>(Point(pos.x + 175, pos.y + 100), hero);
+		GH.windows().pushIntT<CInfoBoxPopup>(Point(pos.x + 175, pos.y + 100), hero);
 	}
 }
 
@@ -696,7 +697,7 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil
 		case BuildingID::FORT:
 		case BuildingID::CITADEL:
 		case BuildingID::CASTLE:
-				GH.pushIntT<CFortScreen>(town);
+				GH.windows().pushIntT<CFortScreen>(town);
 				break;
 
 		case BuildingID::VILLAGE_HALL:
@@ -707,7 +708,7 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil
 				break;
 
 		case BuildingID::MARKETPLACE:
-				GH.pushIntT<CMarketplaceWindow>(town, town->visitingHero);
+				GH.windows().pushIntT<CMarketplaceWindow>(town, town->visitingHero);
 				break;
 
 		case BuildingID::BLACKSMITH:
@@ -733,7 +734,7 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil
 
 				case BuildingSubID::ARTIFACT_MERCHANT:
 						if(town->visitingHero)
-							GH.pushIntT<CMarketplaceWindow>(town, town->visitingHero, EMarketMode::RESOURCE_ARTIFACT);
+							GH.windows().pushIntT<CMarketplaceWindow>(town, town->visitingHero, EMarketMode::RESOURCE_ARTIFACT);
 						else
 							LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[273]) % b->getNameTranslated())); //Only visiting heroes may use the %s.
 						break;
@@ -744,14 +745,14 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil
 
 				case BuildingSubID::FREELANCERS_GUILD:
 						if(getHero())
-							GH.pushIntT<CMarketplaceWindow>(town, getHero(), EMarketMode::CREATURE_RESOURCE);
+							GH.windows().pushIntT<CMarketplaceWindow>(town, getHero(), EMarketMode::CREATURE_RESOURCE);
 						else
 							LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[273]) % b->getNameTranslated())); //Only visiting heroes may use the %s.
 						break;
 
 				case BuildingSubID::MAGIC_UNIVERSITY:
 						if (getHero())
-							GH.pushIntT<CUniversityWindow>(getHero(), town);
+							GH.windows().pushIntT<CUniversityWindow>(getHero(), town);
 						else
 							enterBuilding(building);
 						break;
@@ -768,7 +769,7 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil
 						break;
 
 				case BuildingSubID::CREATURE_TRANSFORMER: //Skeleton Transformer
-						GH.pushIntT<CTransformerWindow>(town, getHero());
+						GH.windows().pushIntT<CTransformerWindow>(town, getHero());
 						break;
 
 				case BuildingSubID::PORTAL_OF_SUMMONING:
@@ -823,7 +824,7 @@ void CCastleBuildings::enterBlacksmith(ArtifactID artifactID)
 		}
 	}
 	CreatureID cre = art->getWarMachine();
-	GH.pushIntT<CBlacksmithDialog>(possible, cre, artifactID, hero->id);
+	GH.windows().pushIntT<CBlacksmithDialog>(possible, cre, artifactID, hero->id);
 }
 
 void CCastleBuildings::enterBuilding(BuildingID building)
@@ -852,7 +853,7 @@ void CCastleBuildings::enterCastleGate()
 		}
 	}
 	auto gateIcon = std::make_shared<CAnimImage>(town->town->clientInfo.buildingsIcons, BuildingID::CASTLE_GATE);//will be deleted by selection window
-	GH.pushIntT<CObjectListWindow>(availableTowns, gateIcon, CGI->generaltexth->jktexts[40],
+	GH.windows().pushIntT<CObjectListWindow>(availableTowns, gateIcon, CGI->generaltexth->jktexts[40],
 		CGI->generaltexth->jktexts[41], std::bind (&CCastleInterface::castleTeleport, LOCPLINT->castleInt, _1));
 }
 
@@ -863,7 +864,7 @@ void CCastleBuildings::enterDwelling(int level)
 	{
 		LOCPLINT->cb->recruitCreatures(town, town->getUpperArmy(), id, count, level);
 	};
-	GH.pushIntT<CRecruitmentWindow>(town, level, town, recruitCb, -87);
+	GH.windows().pushIntT<CRecruitmentWindow>(town, level, town, recruitCb, -87);
 }
 
 void CCastleBuildings::enterToTheQuickRecruitmentWindow()
@@ -875,7 +876,7 @@ void CCastleBuildings::enterToTheQuickRecruitmentWindow()
 	const auto hasSomeoneToRecruit = std::any_of(beginIt, afterLastIt,
 		[](const auto & creatureInfo) { return creatureInfo.first > 0; });
 	if(hasSomeoneToRecruit)
-		GH.pushIntT<QuickRecruitmentWindow>(town, pos);
+		GH.windows().pushIntT<QuickRecruitmentWindow>(town, pos);
 	else
 		CInfoWindow::showInfoDialog(CGI->generaltexth->translate("vcmi.townHall.noCreaturesToRecruit"), {});
 }
@@ -973,7 +974,7 @@ void CCastleBuildings::enterTownHall()
 		else
 		{
 			LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[673]);
-			dynamic_cast<CInfoWindow*>(GH.topInt().get())->buttons[0]->addCallback(std::bind(&CCastleBuildings::openTownHall, this));
+			dynamic_cast<CInfoWindow*>(GH.windows().topInt().get())->buttons[0]->addCallback(std::bind(&CCastleBuildings::openTownHall, this));
 		}
 	}
 	else
@@ -986,12 +987,12 @@ void CCastleBuildings::openMagesGuild()
 {
 	std::string mageGuildBackground;
 	mageGuildBackground = LOCPLINT->castleInt->town->town->clientInfo.guildBackground;
-	GH.pushIntT<CMageGuildScreen>(LOCPLINT->castleInt,mageGuildBackground);
+	GH.windows().pushIntT<CMageGuildScreen>(LOCPLINT->castleInt,mageGuildBackground);
 }
 
 void CCastleBuildings::openTownHall()
 {
-	GH.pushIntT<CHallInterface>(town);
+	GH.windows().pushIntT<CHallInterface>(town);
 }
 
 CCreaInfo::CCreaInfo(Point position, const CGTownInstance * Town, int Level, bool compact, bool _showAvailable):
@@ -1074,7 +1075,7 @@ void CCreaInfo::clickLeft(tribool down, bool previousState)
 		{
 			LOCPLINT->cb->recruitCreatures(town, town->getUpperArmy(), id, count, level);
 		};
-		GH.pushIntT<CRecruitmentWindow>(town, level, town, recruitCb, offset);
+		GH.windows().pushIntT<CRecruitmentWindow>(town, level, town, recruitCb, offset);
 	}
 }
 
@@ -1094,7 +1095,7 @@ void CCreaInfo::clickRight(tribool down, bool previousState)
 	if(down)
 	{
 		if (showAvailable)
-			GH.pushIntT<CDwellingInfoBox>(GH.screenDimensions().x / 2, GH.screenDimensions().y / 2, town, level);
+			GH.windows().pushIntT<CDwellingInfoBox>(GH.screenDimensions().x / 2, GH.screenDimensions().y / 2, town, level);
 		else
 			CRClickPopup::createAndPush(genGrowthText(), std::make_shared<CComponent>(CComponent::creature, creature->getId()));
 	}
@@ -1253,7 +1254,7 @@ void CCastleInterface::townChange()
 	if ( dest == town )
 		return;
 	close();
-	GH.pushIntT<CCastleInterface>(dest, town);
+	GH.windows().pushIntT<CCastleInterface>(dest, town);
 }
 
 void CCastleInterface::addBuilding(BuildingID bid)
@@ -1393,13 +1394,13 @@ void CHallInterface::CBuildingBox::hover(bool on)
 void CHallInterface::CBuildingBox::clickLeft(tribool down, bool previousState)
 {
 	if(previousState && (!down))
-		GH.pushIntT<CBuildWindow>(town,building,state,0);
+		GH.windows().pushIntT<CBuildWindow>(town,building,state,0);
 }
 
 void CHallInterface::CBuildingBox::clickRight(tribool down, bool previousState)
 {
 	if(down)
-		GH.pushIntT<CBuildWindow>(town,building,state,1);
+		GH.windows().pushIntT<CBuildWindow>(town,building,state,1);
 }
 
 CHallInterface::CHallInterface(const CGTownInstance * Town):
@@ -1493,7 +1494,7 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
 void CBuildWindow::buyFunc()
 {
 	LOCPLINT->cb->buildBuilding(town,building->bid);
-	GH.popInts(2); //we - build window and hall screen
+	GH.windows().popInts(2); //we - build window and hall screen
 }
 
 std::string CBuildWindow::getTextForState(int state)

+ 5 - 4
client/windows/CHeroWindow.cpp

@@ -20,6 +20,7 @@
 #include "../gui/CGuiHandler.h"
 #include "../gui/TextAlignment.h"
 #include "../gui/Shortcut.h"
+#include "../gui/WindowHandler.h"
 #include "../widgets/MiscWidgets.h"
 #include "../widgets/CComponent.h"
 #include "../widgets/TextControls.h"
@@ -96,8 +97,8 @@ void CHeroSwitcher::clickLeft(tribool down, bool previousState)
 		else
 		{
 			const CGHeroInstance * buf = hero;
-			GH.popInts(1);
-			GH.pushIntT<CHeroWindow>(buf);
+			GH.windows().popInts(1);
+			GH.windows().pushIntT<CHeroWindow>(buf);
 		}
 	}
 }
@@ -313,7 +314,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded)
 
 	//if we have exchange window with this curHero open
 	bool noDismiss=false;
-	for(auto isa : GH.listInt)
+	for(auto isa : GH.windows().listInt)
 	{
 		if(CExchangeWindow * cew = dynamic_cast<CExchangeWindow*>(isa.get()))
 		{
@@ -389,7 +390,7 @@ void CHeroWindow::commanderWindow()
 	}
 	else
 	{
-		GH.pushIntT<CStackWindow>(curHero->commander, false);
+		GH.windows().pushIntT<CStackWindow>(curHero->commander, false);
 	}
 }
 

+ 2 - 1
client/windows/CSpellWindow.cpp

@@ -24,6 +24,7 @@
 #include "../battle/BattleInterface.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/Shortcut.h"
+#include "../gui/WindowHandler.h"
 #include "../widgets/MiscWidgets.h"
 #include "../widgets/CComponent.h"
 #include "../widgets/TextControls.h"
@@ -525,7 +526,7 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
 		else //adventure spell
 		{
 			const CGHeroInstance * h = owner->myHero;
-			GH.popInts(1);
+			GH.windows().popInts(1);
 
 			auto guard = vstd::makeScopeGuard([this]()
 			{

+ 3 - 2
client/windows/CTradeWindow.cpp

@@ -16,6 +16,7 @@
 #include "../renderSDL/SDL_Extensions.h"
 #include "../gui/TextAlignment.h"
 #include "../gui/Shortcut.h"
+#include "../gui/WindowHandler.h"
 #include "../widgets/Buttons.h"
 #include "../widgets/TextControls.h"
 #include "../windows/InfoWindows.h"
@@ -628,10 +629,10 @@ void CTradeWindow::setMode(EMarketMode::EMarketMode Mode)
 	{
 	case EMarketMode::CREATURE_EXP:
 	case EMarketMode::ARTIFACT_EXP:
-		GH.pushIntT<CAltarWindow>(m, h, Mode);
+		GH.windows().pushIntT<CAltarWindow>(m, h, Mode);
 		break;
 	default:
-		GH.pushIntT<CMarketplaceWindow>(m, h, Mode);
+		GH.windows().pushIntT<CMarketplaceWindow>(m, h, Mode);
 		break;
 	}
 }

+ 2 - 1
client/windows/CreaturePurchaseCard.cpp

@@ -17,6 +17,7 @@
 #include "../gui/CGuiHandler.h"
 #include "../gui/Shortcut.h"
 #include "../gui/TextAlignment.h"
+#include "../gui/WindowHandler.h"
 #include "../widgets/Buttons.h"
 #include "../widgets/TextControls.h"
 #include "../widgets/CreatureCostBox.h"
@@ -124,5 +125,5 @@ CreaturePurchaseCard::CCreatureClickArea::CCreatureClickArea(const Point & posit
 void CreaturePurchaseCard::CCreatureClickArea::clickRight(tribool down, bool previousState)
 {
 	if (down)
-		GH.pushIntT<CStackWindow>(creatureOnTheCard, true);
+		GH.windows().pushIntT<CStackWindow>(creatureOnTheCard, true);
 }

+ 5 - 4
client/windows/GUIClasses.cpp

@@ -29,6 +29,7 @@
 #include "../gui/CursorHandler.h"
 #include "../gui/TextAlignment.h"
 #include "../gui/Shortcut.h"
+#include "../gui/WindowHandler.h"
 
 #include "../widgets/CComponent.h"
 #include "../widgets/MiscWidgets.h"
@@ -98,7 +99,7 @@ void CRecruitmentWindow::CCreatureCard::clickLeft(tribool down, bool previousSta
 void CRecruitmentWindow::CCreatureCard::clickRight(tribool down, bool previousState)
 {
 	if(down)
-		GH.pushIntT<CStackWindow>(creature, true);
+		GH.windows().pushIntT<CStackWindow>(creature, true);
 }
 
 void CRecruitmentWindow::CCreatureCard::showAll(SDL_Surface * to)
@@ -507,7 +508,7 @@ void CTavernWindow::recruitb()
 
 void CTavernWindow::thievesguildb()
 {
-	GH.pushIntT<CThievesGuildWindow>(tavernObj);
+	GH.windows().pushIntT<CThievesGuildWindow>(tavernObj);
 }
 
 CTavernWindow::~CTavernWindow()
@@ -547,7 +548,7 @@ void CTavernWindow::HeroPortrait::clickLeft(tribool down, bool previousState)
 void CTavernWindow::HeroPortrait::clickRight(tribool down, bool previousState)
 {
 	if(h && down)
-		GH.pushIntT<CRClickPopupInt>(std::make_shared<CHeroWindow>(h));
+		GH.windows().pushIntT<CRClickPopupInt>(std::make_shared<CHeroWindow>(h));
 }
 
 CTavernWindow::HeroPortrait::HeroPortrait(int & sel, int id, int x, int y, const CGHeroInstance * H)
@@ -1240,7 +1241,7 @@ void CUniversityWindow::CItem::clickLeft(tribool down, bool previousState)
 	if(previousState && (!down))
 	{
 		if(state() == 2)
-			GH.pushIntT<CUnivConfirmWindow>(parent, ID, LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) >= 2000);
+			GH.windows().pushIntT<CUnivConfirmWindow>(parent, ID, LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) >= 2000);
 	}
 }
 

+ 5 - 4
client/windows/InfoWindows.cpp

@@ -20,6 +20,7 @@
 #include "../widgets/Buttons.h"
 #include "../widgets/TextControls.h"
 #include "../gui/CGuiHandler.h"
+#include "../gui/WindowHandler.h"
 #include "../battle/BattleInterface.h"
 #include "../battle/BattleInterfaceClasses.h"
 #include "../adventureMap/AdventureMapInterface.h"
@@ -182,7 +183,7 @@ void CInfoWindow::showAll(SDL_Surface * to)
 
 void CInfoWindow::showInfoDialog(const std::string &text, const TCompsInfo & components, PlayerColor player)
 {
-	GH.pushInt(CInfoWindow::create(text, player, components));
+	GH.windows().pushInt(CInfoWindow::create(text, player, components));
 }
 
 void CInfoWindow::showYesNoDialog(const std::string & text, const TCompsInfo & components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, PlayerColor player)
@@ -196,7 +197,7 @@ void CInfoWindow::showYesNoDialog(const std::string & text, const TCompsInfo & c
 	temp->buttons[0]->addCallback( onYes );
 	temp->buttons[1]->addCallback( onNo );
 
-	GH.pushInt(temp);
+	GH.windows().pushInt(temp);
 }
 
 std::shared_ptr<CInfoWindow> CInfoWindow::create(const std::string &text, PlayerColor playerID, const TCompsInfo & components)
@@ -313,7 +314,7 @@ void CRClickPopup::createAndPush(const std::string &txt, const CInfoWindow::TCom
 #endif
 	temp->fitToScreen(10);
 
-	GH.pushIntT<CRClickPopupInt>(temp);
+	GH.windows().pushIntT<CRClickPopupInt>(temp);
 }
 
 void CRClickPopup::createAndPush(const std::string & txt, std::shared_ptr<CComponent> component)
@@ -329,7 +330,7 @@ void CRClickPopup::createAndPush(const CGObjectInstance * obj, const Point & p,
 	auto iWin = createInfoWin(p, obj); //try get custom infowindow for this obj
 	if(iWin)
 	{
-		GH.pushInt(iWin);
+		GH.windows().pushInt(iWin);
 	}
 	else
 	{

+ 3 - 2
client/windows/settings/GeneralOptionsTab.cpp

@@ -14,6 +14,7 @@
 #include "../../../lib/CGeneralTextHandler.h"
 #include "../../../lib/filesystem/ResourceID.h"
 #include "../../gui/CGuiHandler.h"
+#include "../../gui/WindowHandler.h"
 #include "../../widgets/Buttons.h"
 #include "../../widgets/TextControls.h"
 #include "../../widgets/Images.h"
@@ -197,7 +198,7 @@ void GeneralOptionsTab::selectGameResolution()
 		items.push_back(std::move(resolutionStr));
 		++i;
 	}
-	GH.pushIntT<CObjectListWindow>(items, nullptr,
+	GH.windows().pushIntT<CObjectListWindow>(items, nullptr,
 								   CGI->generaltexth->translate("vcmi.systemOptions.resolutionMenu.hover"),
 								   CGI->generaltexth->translate("vcmi.systemOptions.resolutionMenu.help"),
 								   [this](int index)
@@ -252,7 +253,7 @@ void GeneralOptionsTab::selectGameScaling()
 		++i;
 	}
 
-	GH.pushIntT<CObjectListWindow>(
+	GH.windows().pushIntT<CObjectListWindow>(
 		items,
 		nullptr,
 		CGI->generaltexth->translate("vcmi.systemOptions.scalingMenu.hover"),

+ 4 - 3
client/windows/settings/SettingsMainWindow.cpp

@@ -22,6 +22,7 @@
 #include "CServerHandler.h"
 #include "filesystem/ResourceID.h"
 #include "gui/CGuiHandler.h"
+#include "gui/WindowHandler.h"
 #include "lobby/CSavingScreen.h"
 #include "widgets/Buttons.h"
 #include "widgets/Images.h"
@@ -103,9 +104,9 @@ void SettingsMainWindow::openTab(size_t index)
 
 void SettingsMainWindow::close()
 {
-	if(GH.topInt().get() != this)
+	if(GH.windows().topInt().get() != this)
 		logGlobal->error("Only top interface must be closed");
-	GH.popInts(1);
+	GH.windows().popInts(1);
 }
 
 void SettingsMainWindow::quitGameButtonCallback()
@@ -132,7 +133,7 @@ void SettingsMainWindow::loadGameButtonCallback()
 void SettingsMainWindow::saveGameButtonCallback()
 {
 	close();
-	GH.pushIntT<CSavingScreen>();
+	GH.windows().pushIntT<CSavingScreen>();
 }
 
 void SettingsMainWindow::restartGameButtonCallback()