1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Managers/BsRenderWindowManager.h"
4#include "Platform/BsPlatform.h"
5#include "BsCoreApplication.h"
6
7using namespace std::placeholders;
8
9namespace bs
10{
11 SPtr<RenderWindow> RenderWindowManager::create(RENDER_WINDOW_DESC& desc, SPtr<RenderWindow> parentWindow)
12 {
13 UINT32 id = ct::RenderWindowManager::instance().mNextWindowId.fetch_add(1, std::memory_order_relaxed);
14
15 SPtr<RenderWindow> renderWindow = createImpl(desc, id, parentWindow);
16 renderWindow->_setThisPtr(renderWindow);
17
18 {
19 Lock lock(mWindowMutex);
20
21 mWindows[renderWindow->mWindowId] = renderWindow.get();
22 }
23
24 if (renderWindow->getProperties().isModal)
25 mModalWindowStack.push_back(renderWindow.get());
26
27 renderWindow->initialize();
28
29 return renderWindow;
30 }
31
32 void RenderWindowManager::notifyWindowDestroyed(RenderWindow* window)
33 {
34 {
35 Lock lock(mWindowMutex);
36
37 auto iterFind = std::find(begin(mMovedOrResizedWindows), end(mMovedOrResizedWindows), window);
38
39 if(iterFind != mMovedOrResizedWindows.end())
40 mMovedOrResizedWindows.erase(iterFind);
41
42 if (mNewWindowInFocus == window)
43 mNewWindowInFocus = nullptr;
44
45 mWindows.erase(window->mWindowId);
46 mDirtyProperties.erase(window);
47 }
48
49 {
50 auto iterFind = std::find(begin(mModalWindowStack), end(mModalWindowStack), window);
51 if(iterFind != mModalWindowStack.end())
52 mModalWindowStack.erase(iterFind);
53 }
54 }
55
56 void RenderWindowManager::notifyFocusReceived(ct::RenderWindow* coreWindow)
57 {
58 Lock lock(mWindowMutex);
59
60 RenderWindow* window = getNonCore(coreWindow);
61 mNewWindowInFocus = window;
62 }
63
64 void RenderWindowManager::notifyFocusLost(ct::RenderWindow* coreWindow)
65 {
66 Lock lock(mWindowMutex);
67
68 mNewWindowInFocus = nullptr;
69 }
70
71 void RenderWindowManager::notifyMovedOrResized(ct::RenderWindow* coreWindow)
72 {
73 Lock lock(mWindowMutex);
74
75 RenderWindow* window = getNonCore(coreWindow);
76 if (window == nullptr)
77 return;
78
79 auto iterFind = std::find(begin(mMovedOrResizedWindows), end(mMovedOrResizedWindows), window);
80 if (iterFind == end(mMovedOrResizedWindows))
81 mMovedOrResizedWindows.push_back(window);
82 }
83
84 void RenderWindowManager::notifyMouseLeft(ct::RenderWindow* coreWindow)
85 {
86 Lock lock(mWindowMutex);
87
88 RenderWindow* window = getNonCore(coreWindow);
89 auto iterFind = std::find(begin(mMouseLeftWindows), end(mMouseLeftWindows), window);
90
91 if (iterFind == end(mMouseLeftWindows))
92 mMouseLeftWindows.push_back(window);
93 }
94
95 void RenderWindowManager::notifyCloseRequested(ct::RenderWindow* coreWindow)
96 {
97 Lock lock(mWindowMutex);
98
99 RenderWindow* window = getNonCore(coreWindow);
100 auto iterFind = std::find(begin(mCloseRequestedWindows), end(mCloseRequestedWindows), window);
101
102 if (iterFind == end(mCloseRequestedWindows))
103 mCloseRequestedWindows.push_back(window);
104 }
105
106 void RenderWindowManager::notifySyncDataDirty(ct::RenderWindow* coreWindow)
107 {
108 Lock lock(mWindowMutex);
109
110 RenderWindow* window = getNonCore(coreWindow);
111
112 if (window != nullptr)
113 mDirtyProperties.insert(window);
114 }
115
116 void RenderWindowManager::_update()
117 {
118 RenderWindow* newWinInFocus = nullptr;
119 Vector<RenderWindow*> movedOrResizedWindows;
120 Vector<RenderWindow*> mouseLeftWindows;
121 Vector<RenderWindow*> closeRequestedWindows;
122
123 {
124 Lock lock(mWindowMutex);
125 newWinInFocus = mNewWindowInFocus;
126
127 std::swap(mMovedOrResizedWindows, movedOrResizedWindows);
128 std::swap(mMouseLeftWindows, mouseLeftWindows);
129
130 for (auto& dirtyPropertyWindow : mDirtyProperties)
131 dirtyPropertyWindow->syncProperties();
132
133 mDirtyProperties.clear();
134
135 std::swap(mCloseRequestedWindows, closeRequestedWindows);
136 }
137
138 if(mWindowInFocus != newWinInFocus)
139 {
140 if(mWindowInFocus != nullptr)
141 onFocusLost(*mWindowInFocus);
142
143 if(newWinInFocus != nullptr)
144 onFocusGained(*newWinInFocus);
145
146 mWindowInFocus = newWinInFocus;
147 }
148
149 for (auto& window : movedOrResizedWindows)
150 window->onResized();
151
152 if (!onMouseLeftWindow.empty())
153 {
154 for (auto& window : mouseLeftWindows)
155 onMouseLeftWindow(*window);
156 }
157
158 SPtr<RenderWindow> primaryWindow = gCoreApplication().getPrimaryWindow();
159 for(auto& entry : closeRequestedWindows)
160 {
161 // Default behaviour for primary window is to quit the app on close
162 if(entry == primaryWindow.get() && entry->onCloseRequested.empty())
163 {
164 gCoreApplication().quitRequested();
165 continue;
166 }
167
168 entry->onCloseRequested();
169 }
170 }
171
172 Vector<RenderWindow*> RenderWindowManager::getRenderWindows() const
173 {
174 Lock lock(mWindowMutex);
175
176 Vector<RenderWindow*> windows;
177 for (auto& windowPair : mWindows)
178 windows.push_back(windowPair.second);
179
180 return windows;
181 }
182
183 RenderWindow* RenderWindowManager::getTopMostModal() const
184 {
185 if (mModalWindowStack.empty())
186 return nullptr;
187
188 return mModalWindowStack.back();
189 }
190
191 RenderWindow* RenderWindowManager::getNonCore(const ct::RenderWindow* window) const
192 {
193 auto iterFind = mWindows.find(window->mWindowId);
194
195 if (iterFind != mWindows.end())
196 return iterFind->second;
197
198 return nullptr;
199 }
200
201 namespace ct
202 {
203
204 RenderWindowManager::RenderWindowManager()
205 {
206 mNextWindowId = 0;
207 }
208
209 void RenderWindowManager::_update()
210 {
211 Lock lock(mWindowMutex);
212
213 for (auto& dirtyPropertyWindow : mDirtyProperties)
214 dirtyPropertyWindow->syncProperties();
215
216 mDirtyProperties.clear();
217 }
218
219 void RenderWindowManager::windowCreated(RenderWindow* window)
220 {
221 Lock lock(mWindowMutex);
222
223 mCreatedWindows.push_back(window);
224 }
225
226 void RenderWindowManager::windowDestroyed(RenderWindow* window)
227 {
228 {
229 Lock lock(mWindowMutex);
230
231 auto iterFind = std::find(begin(mCreatedWindows), end(mCreatedWindows), window);
232
233 if (iterFind == mCreatedWindows.end())
234 BS_EXCEPT(InternalErrorException, "Trying to destroy a window that is not in the created windows list.");
235
236 mCreatedWindows.erase(iterFind);
237 mDirtyProperties.erase(window);
238 }
239 }
240
241 Vector<RenderWindow*> RenderWindowManager::getRenderWindows() const
242 {
243 Lock lock(mWindowMutex);
244
245 return mCreatedWindows;
246 }
247
248 void RenderWindowManager::notifySyncDataDirty(RenderWindow* window)
249 {
250 Lock lock(mWindowMutex);
251
252 mDirtyProperties.insert(window);
253 }
254 }
255}