1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9 #include "GUIWindowManager.h"
10
11 #include "Application.h"
12 #include "GUIAudioManager.h"
13 #include "GUIDialog.h"
14 #include "GUIInfoManager.h"
15 #include "GUIPassword.h"
16 #include "GUITexture.h"
17 #include "addons/Skin.h"
18 #include "addons/gui/GUIWindowAddonBrowser.h"
19 #include "addons/interfaces/gui/Window.h"
20 #include "events/windows/GUIWindowEventLog.h"
21 #include "favourites/GUIDialogFavourites.h"
22 #include "input/Key.h"
23 #include "messaging/ApplicationMessenger.h"
24 #include "messaging/helpers/DialogHelper.h"
25 #include "music/dialogs/GUIDialogInfoProviderSettings.h"
26 #include "music/dialogs/GUIDialogMusicInfo.h"
27 #include "music/windows/GUIWindowMusicNav.h"
28 #include "music/windows/GUIWindowMusicPlaylist.h"
29 #include "music/windows/GUIWindowMusicPlaylistEditor.h"
30 #include "music/windows/GUIWindowVisualisation.h"
31 #include "pictures/GUIWindowPictures.h"
32 #include "pictures/GUIWindowSlideShow.h"
33 #include "profiles/windows/GUIWindowSettingsProfile.h"
34 #include "programs/GUIWindowPrograms.h"
35 #include "settings/AdvancedSettings.h"
36 #include "settings/SettingsComponent.h"
37 #include "settings/windows/GUIWindowSettings.h"
38 #include "settings/windows/GUIWindowSettingsCategory.h"
39 #include "settings/windows/GUIWindowSettingsScreenCalibration.h"
40 #include "threads/SingleLock.h"
41 #include "utils/StringUtils.h"
42 #include "utils/URIUtils.h"
43 #include "utils/Variant.h"
44 #include "utils/log.h"
45 #include "video/dialogs/GUIDialogVideoInfo.h"
46 #include "video/dialogs/GUIDialogVideoOSD.h"
47 #include "video/windows/GUIWindowFullScreen.h"
48 #include "video/windows/GUIWindowVideoNav.h"
49 #include "video/windows/GUIWindowVideoPlaylist.h"
50 #include "weather/GUIWindowWeather.h"
51 #include "windows/GUIWindowDebugInfo.h"
52 #include "windows/GUIWindowFileManager.h"
53 #include "windows/GUIWindowHome.h"
54 #include "windows/GUIWindowLoginScreen.h"
55 #include "windows/GUIWindowPointer.h"
56 #include "windows/GUIWindowScreensaver.h"
57 #include "windows/GUIWindowScreensaverDim.h"
58 #include "windows/GUIWindowSplash.h"
59 #include "windows/GUIWindowStartup.h"
60 #include "windows/GUIWindowSystemInfo.h"
61
62 // Dialog includes
63 #include "music/dialogs/GUIDialogMusicOSD.h"
64 #include "music/dialogs/GUIDialogVisualisationPresetList.h"
65 #include "dialogs/GUIDialogTextViewer.h"
66 #include "network/GUIDialogNetworkSetup.h"
67 #include "dialogs/GUIDialogMediaSource.h"
68 #if defined(HAS_GL) || defined(HAS_DX)
69 #include "video/dialogs/GUIDialogCMSSettings.h"
70 #endif
71 #include "addons/gui/GUIDialogAddonInfo.h"
72 #include "addons/gui/GUIDialogAddonSettings.h"
73 #include "dialogs/GUIDialogBusy.h"
74 #include "dialogs/GUIDialogBusyNoCancel.h"
75 #include "dialogs/GUIDialogButtonMenu.h"
76 #include "dialogs/GUIDialogContextMenu.h"
77 #include "dialogs/GUIDialogExtendedProgressBar.h"
78 #include "dialogs/GUIDialogGamepad.h"
79 #include "dialogs/GUIDialogKaiToast.h"
80 #include "dialogs/GUIDialogKeyboardGeneric.h"
81 #include "dialogs/GUIDialogKeyboardTouch.h"
82 #include "dialogs/GUIDialogNumeric.h"
83 #include "dialogs/GUIDialogOK.h"
84 #include "dialogs/GUIDialogPlayerControls.h"
85 #include "dialogs/GUIDialogPlayerProcessInfo.h"
86 #include "dialogs/GUIDialogProgress.h"
87 #include "dialogs/GUIDialogSeekBar.h"
88 #include "dialogs/GUIDialogSelect.h"
89 #include "dialogs/GUIDialogSmartPlaylistEditor.h"
90 #include "dialogs/GUIDialogSmartPlaylistRule.h"
91 #include "dialogs/GUIDialogSubMenu.h"
92 #include "dialogs/GUIDialogVolumeBar.h"
93 #include "dialogs/GUIDialogYesNo.h"
94 #include "music/dialogs/GUIDialogSongInfo.h"
95 #include "pictures/GUIDialogPictureInfo.h"
96 #include "profiles/dialogs/GUIDialogLockSettings.h"
97 #include "profiles/dialogs/GUIDialogProfileSettings.h"
98 #include "settings/dialogs/GUIDialogContentSettings.h"
99 #include "settings/dialogs/GUIDialogLibExportSettings.h"
100 #include "video/dialogs/GUIDialogAudioSettings.h"
101 #include "video/dialogs/GUIDialogSubtitleSettings.h"
102 #include "video/dialogs/GUIDialogVideoBookmarks.h"
103 #include "video/dialogs/GUIDialogVideoSettings.h"
104
105 /* PVR related include Files */
106 #include "pvr/PVRManager.h"
107 #include "pvr/dialogs/GUIDialogPVRChannelGuide.h"
108 #include "pvr/dialogs/GUIDialogPVRChannelManager.h"
109 #include "pvr/dialogs/GUIDialogPVRChannelsOSD.h"
110 #include "pvr/dialogs/GUIDialogPVRClientPriorities.h"
111 #include "pvr/dialogs/GUIDialogPVRGroupManager.h"
112 #include "pvr/dialogs/GUIDialogPVRGuideControls.h"
113 #include "pvr/dialogs/GUIDialogPVRGuideInfo.h"
114 #include "pvr/dialogs/GUIDialogPVRGuideSearch.h"
115 #include "pvr/dialogs/GUIDialogPVRRadioRDSInfo.h"
116 #include "pvr/dialogs/GUIDialogPVRRecordingInfo.h"
117 #include "pvr/dialogs/GUIDialogPVRRecordingSettings.h"
118 #include "pvr/dialogs/GUIDialogPVRTimerSettings.h"
119 #include "pvr/windows/GUIWindowPVRChannels.h"
120 #include "pvr/windows/GUIWindowPVRGuide.h"
121 #include "pvr/windows/GUIWindowPVRRecordings.h"
122 #include "pvr/windows/GUIWindowPVRSearch.h"
123 #include "pvr/windows/GUIWindowPVRTimerRules.h"
124 #include "pvr/windows/GUIWindowPVRTimers.h"
125
126 #include "video/dialogs/GUIDialogTeletext.h"
127 #include "dialogs/GUIDialogSlider.h"
128 #include "dialogs/GUIDialogPlayEject.h"
129 #include "dialogs/GUIDialogMediaFilter.h"
130 #include "video/dialogs/GUIDialogSubtitles.h"
131
132 #include "peripherals/dialogs/GUIDialogPeripherals.h"
133 #include "peripherals/dialogs/GUIDialogPeripheralSettings.h"
134
135 /* Game related include files */
136 #include "cores/RetroPlayer/guiwindows/GameWindowFullScreen.h"
137 #include "games/controllers/windows/GUIControllerWindow.h"
138 #include "games/windows/GUIWindowGames.h"
139 #include "games/dialogs/osd/DialogGameAdvancedSettings.h"
140 #include "games/dialogs/osd/DialogGameOSD.h"
141 #include "games/dialogs/osd/DialogGameStretchMode.h"
142 #include "games/dialogs/osd/DialogGameVideoFilter.h"
143 #include "games/dialogs/osd/DialogGameVideoRotation.h"
144 #include "games/dialogs/osd/DialogGameVolume.h"
145
146 using namespace KODI;
147 using namespace PVR;
148 using namespace PERIPHERALS;
149 using namespace MESSAGING;
150
CGUIWindowManager()151 CGUIWindowManager::CGUIWindowManager()
152 {
153 m_pCallback = nullptr;
154 m_iNested = 0;
155 m_initialized = false;
156 }
157
158 CGUIWindowManager::~CGUIWindowManager() = default;
159
Initialize()160 void CGUIWindowManager::Initialize()
161 {
162 m_tracker.SelectAlgorithm();
163
164 m_initialized = true;
165
166 LoadNotOnDemandWindows();
167
168 CApplicationMessenger::GetInstance().RegisterReceiver(this);
169 }
170
CreateWindows()171 void CGUIWindowManager::CreateWindows()
172 {
173 Add(new CGUIWindowHome);
174 Add(new CGUIWindowPrograms);
175 Add(new CGUIWindowPictures);
176 Add(new CGUIWindowFileManager);
177 Add(new CGUIWindowSettings);
178 Add(new CGUIWindowSystemInfo);
179 Add(new CGUIWindowSettingsScreenCalibration);
180 Add(new CGUIWindowSettingsCategory);
181 Add(new CGUIWindowVideoNav);
182 Add(new CGUIWindowVideoPlaylist);
183 Add(new CGUIWindowLoginScreen);
184 Add(new CGUIWindowSettingsProfile);
185 Add(new CGUIWindow(WINDOW_SKIN_SETTINGS, "SkinSettings.xml"));
186 Add(new CGUIWindowAddonBrowser);
187 Add(new CGUIWindowScreensaverDim);
188 Add(new CGUIWindowDebugInfo);
189 Add(new CGUIWindowPointer);
190 Add(new CGUIDialogYesNo);
191 Add(new CGUIDialogProgress);
192 Add(new CGUIDialogExtendedProgressBar);
193 Add(new CGUIDialogKeyboardGeneric);
194 Add(new CGUIDialogKeyboardTouch);
195 Add(new CGUIDialogVolumeBar);
196 Add(new CGUIDialogSeekBar);
197 Add(new CGUIDialogSubMenu);
198 Add(new CGUIDialogContextMenu);
199 Add(new CGUIDialogKaiToast);
200 Add(new CGUIDialogNumeric);
201 Add(new CGUIDialogGamepad);
202 Add(new CGUIDialogButtonMenu);
203 Add(new CGUIDialogPlayerControls);
204 Add(new CGUIDialogPlayerProcessInfo);
205 Add(new CGUIDialogSlider);
206 Add(new CGUIDialogMusicOSD);
207 Add(new CGUIDialogVisualisationPresetList);
208 #if defined(HAS_GL) || defined(HAS_DX)
209 Add(new CGUIDialogCMSSettings);
210 #endif
211 Add(new CGUIDialogVideoSettings);
212 Add(new CGUIDialogAudioSettings);
213 Add(new CGUIDialogSubtitleSettings);
214 Add(new CGUIDialogVideoBookmarks);
215 // Don't add the filebrowser dialog - it's created and added when it's needed
216 Add(new CGUIDialogNetworkSetup);
217 Add(new CGUIDialogMediaSource);
218 Add(new CGUIDialogProfileSettings);
219 Add(new CGUIDialogFavourites);
220 Add(new CGUIDialogSongInfo);
221 Add(new CGUIDialogSmartPlaylistEditor);
222 Add(new CGUIDialogSmartPlaylistRule);
223 Add(new CGUIDialogBusy);
224 Add(new CGUIDialogBusyNoCancel);
225 Add(new CGUIDialogPictureInfo);
226 Add(new CGUIDialogAddonInfo);
227 Add(new CGUIDialogAddonSettings);
228
229 Add(new CGUIDialogLockSettings);
230
231 Add(new CGUIDialogContentSettings);
232
233 Add(new CGUIDialogLibExportSettings);
234
235 Add(new CGUIDialogInfoProviderSettings);
236
237 Add(new CGUIDialogPlayEject);
238
239 Add(new CGUIDialogPeripherals);
240 Add(new CGUIDialogPeripheralSettings);
241
242 Add(new CGUIDialogMediaFilter);
243 Add(new CGUIDialogSubtitles);
244
245 Add(new CGUIWindowMusicPlayList);
246 Add(new CGUIWindowMusicNav);
247 Add(new CGUIWindowMusicPlaylistEditor);
248
249 /* Load PVR related Windows and Dialogs */
250 Add(new CGUIDialogTeletext);
251 Add(new CGUIWindowPVRTVChannels);
252 Add(new CGUIWindowPVRTVRecordings);
253 Add(new CGUIWindowPVRTVGuide);
254 Add(new CGUIWindowPVRTVTimers);
255 Add(new CGUIWindowPVRTVTimerRules);
256 Add(new CGUIWindowPVRTVSearch);
257 Add(new CGUIWindowPVRRadioChannels);
258 Add(new CGUIWindowPVRRadioRecordings);
259 Add(new CGUIWindowPVRRadioGuide);
260 Add(new CGUIWindowPVRRadioTimers);
261 Add(new CGUIWindowPVRRadioTimerRules);
262 Add(new CGUIWindowPVRRadioSearch);
263 Add(new CGUIDialogPVRRadioRDSInfo);
264 Add(new CGUIDialogPVRGuideInfo);
265 Add(new CGUIDialogPVRRecordingInfo);
266 Add(new CGUIDialogPVRTimerSettings);
267 Add(new CGUIDialogPVRGroupManager);
268 Add(new CGUIDialogPVRChannelManager);
269 Add(new CGUIDialogPVRGuideSearch);
270 Add(new CGUIDialogPVRChannelsOSD);
271 Add(new CGUIDialogPVRChannelGuide);
272 Add(new CGUIDialogPVRRecordingSettings);
273 Add(new CGUIDialogPVRClientPriorities);
274 Add(new CGUIDialogPVRGuideControls);
275
276 Add(new CGUIDialogSelect);
277 Add(new CGUIDialogMusicInfo);
278 Add(new CGUIDialogOK);
279 Add(new CGUIDialogVideoInfo);
280 Add(new CGUIDialogTextViewer);
281 Add(new CGUIWindowFullScreen);
282 Add(new CGUIWindowVisualisation);
283 Add(new CGUIWindowSlideShow);
284
285 Add(new CGUIDialogVideoOSD);
286 Add(new CGUIWindowScreensaver);
287 Add(new CGUIWindowWeather);
288 Add(new CGUIWindowStartup);
289 Add(new CGUIWindowSplash);
290
291 Add(new CGUIWindowEventLog);
292
293 Add(new GAME::CGUIControllerWindow);
294 Add(new GAME::CGUIWindowGames);
295 Add(new GAME::CDialogGameOSD);
296 Add(new GAME::CDialogGameVideoFilter);
297 Add(new GAME::CDialogGameStretchMode);
298 Add(new GAME::CDialogGameVolume);
299 Add(new GAME::CDialogGameAdvancedSettings);
300 Add(new GAME::CDialogGameVideoRotation);
301 Add(new RETRO::CGameWindowFullScreen);
302 }
303
DestroyWindows()304 bool CGUIWindowManager::DestroyWindows()
305 {
306 try
307 {
308 DestroyWindow(WINDOW_SPLASH);
309 DestroyWindow(WINDOW_MUSIC_PLAYLIST);
310 DestroyWindow(WINDOW_MUSIC_PLAYLIST_EDITOR);
311 DestroyWindow(WINDOW_MUSIC_NAV);
312 DestroyWindow(WINDOW_DIALOG_MUSIC_INFO);
313 DestroyWindow(WINDOW_DIALOG_VIDEO_INFO);
314 DestroyWindow(WINDOW_VIDEO_PLAYLIST);
315 DestroyWindow(WINDOW_VIDEO_NAV);
316 DestroyWindow(WINDOW_FILES);
317 DestroyWindow(WINDOW_DIALOG_YES_NO);
318 DestroyWindow(WINDOW_DIALOG_PROGRESS);
319 DestroyWindow(WINDOW_DIALOG_NUMERIC);
320 DestroyWindow(WINDOW_DIALOG_GAMEPAD);
321 DestroyWindow(WINDOW_DIALOG_SUB_MENU);
322 DestroyWindow(WINDOW_DIALOG_BUTTON_MENU);
323 DestroyWindow(WINDOW_DIALOG_CONTEXT_MENU);
324 DestroyWindow(WINDOW_DIALOG_PLAYER_CONTROLS);
325 DestroyWindow(WINDOW_DIALOG_PLAYER_PROCESS_INFO);
326 DestroyWindow(WINDOW_DIALOG_MUSIC_OSD);
327 DestroyWindow(WINDOW_DIALOG_VIS_PRESET_LIST);
328 DestroyWindow(WINDOW_DIALOG_SELECT);
329 DestroyWindow(WINDOW_DIALOG_OK);
330 DestroyWindow(WINDOW_DIALOG_KEYBOARD);
331 DestroyWindow(WINDOW_DIALOG_KEYBOARD_TOUCH);
332 DestroyWindow(WINDOW_FULLSCREEN_VIDEO);
333 DestroyWindow(WINDOW_DIALOG_PROFILE_SETTINGS);
334 DestroyWindow(WINDOW_DIALOG_LOCK_SETTINGS);
335 DestroyWindow(WINDOW_DIALOG_NETWORK_SETUP);
336 DestroyWindow(WINDOW_DIALOG_MEDIA_SOURCE);
337 DestroyWindow(WINDOW_DIALOG_CMS_OSD_SETTINGS);
338 DestroyWindow(WINDOW_DIALOG_VIDEO_OSD_SETTINGS);
339 DestroyWindow(WINDOW_DIALOG_AUDIO_OSD_SETTINGS);
340 DestroyWindow(WINDOW_DIALOG_SUBTITLE_OSD_SETTINGS);
341 DestroyWindow(WINDOW_DIALOG_VIDEO_BOOKMARKS);
342 DestroyWindow(WINDOW_DIALOG_CONTENT_SETTINGS);
343 DestroyWindow(WINDOW_DIALOG_INFOPROVIDER_SETTINGS);
344 DestroyWindow(WINDOW_DIALOG_LIBEXPORT_SETTINGS);
345 DestroyWindow(WINDOW_DIALOG_FAVOURITES);
346 DestroyWindow(WINDOW_DIALOG_SONG_INFO);
347 DestroyWindow(WINDOW_DIALOG_SMART_PLAYLIST_EDITOR);
348 DestroyWindow(WINDOW_DIALOG_SMART_PLAYLIST_RULE);
349 DestroyWindow(WINDOW_DIALOG_BUSY);
350 DestroyWindow(WINDOW_DIALOG_BUSY_NOCANCEL);
351 DestroyWindow(WINDOW_DIALOG_PICTURE_INFO);
352 DestroyWindow(WINDOW_DIALOG_ADDON_INFO);
353 DestroyWindow(WINDOW_DIALOG_ADDON_SETTINGS);
354 DestroyWindow(WINDOW_DIALOG_SLIDER);
355 DestroyWindow(WINDOW_DIALOG_MEDIA_FILTER);
356 DestroyWindow(WINDOW_DIALOG_SUBTITLES);
357
358 /* Delete PVR related windows and dialogs */
359 DestroyWindow(WINDOW_TV_CHANNELS);
360 DestroyWindow(WINDOW_TV_RECORDINGS);
361 DestroyWindow(WINDOW_TV_GUIDE);
362 DestroyWindow(WINDOW_TV_TIMERS);
363 DestroyWindow(WINDOW_TV_TIMER_RULES);
364 DestroyWindow(WINDOW_TV_SEARCH);
365 DestroyWindow(WINDOW_RADIO_CHANNELS);
366 DestroyWindow(WINDOW_RADIO_RECORDINGS);
367 DestroyWindow(WINDOW_RADIO_GUIDE);
368 DestroyWindow(WINDOW_RADIO_TIMERS);
369 DestroyWindow(WINDOW_RADIO_TIMER_RULES);
370 DestroyWindow(WINDOW_RADIO_SEARCH);
371 DestroyWindow(WINDOW_DIALOG_PVR_GUIDE_INFO);
372 DestroyWindow(WINDOW_DIALOG_PVR_RECORDING_INFO);
373 DestroyWindow(WINDOW_DIALOG_PVR_TIMER_SETTING);
374 DestroyWindow(WINDOW_DIALOG_PVR_GROUP_MANAGER);
375 DestroyWindow(WINDOW_DIALOG_PVR_CHANNEL_MANAGER);
376 DestroyWindow(WINDOW_DIALOG_PVR_GUIDE_SEARCH);
377 DestroyWindow(WINDOW_DIALOG_PVR_CHANNEL_SCAN);
378 DestroyWindow(WINDOW_DIALOG_PVR_RADIO_RDS_INFO);
379 DestroyWindow(WINDOW_DIALOG_PVR_UPDATE_PROGRESS);
380 DestroyWindow(WINDOW_DIALOG_PVR_OSD_CHANNELS);
381 DestroyWindow(WINDOW_DIALOG_PVR_CHANNEL_GUIDE);
382 DestroyWindow(WINDOW_DIALOG_OSD_TELETEXT);
383 DestroyWindow(WINDOW_DIALOG_PVR_RECORDING_SETTING);
384 DestroyWindow(WINDOW_DIALOG_PVR_CLIENT_PRIORITIES);
385 DestroyWindow(WINDOW_DIALOG_PVR_GUIDE_CONTROLS);
386
387 DestroyWindow(WINDOW_DIALOG_TEXT_VIEWER);
388 DestroyWindow(WINDOW_DIALOG_PLAY_EJECT);
389 DestroyWindow(WINDOW_STARTUP_ANIM);
390 DestroyWindow(WINDOW_LOGIN_SCREEN);
391 DestroyWindow(WINDOW_VISUALISATION);
392 DestroyWindow(WINDOW_SETTINGS_MENU);
393 DestroyWindow(WINDOW_SETTINGS_PROFILES);
394 DestroyWindow(WINDOW_SCREEN_CALIBRATION);
395 DestroyWindow(WINDOW_SYSTEM_INFORMATION);
396 DestroyWindow(WINDOW_SCREENSAVER);
397 DestroyWindow(WINDOW_DIALOG_VIDEO_OSD);
398 DestroyWindow(WINDOW_SLIDESHOW);
399 DestroyWindow(WINDOW_ADDON_BROWSER);
400 DestroyWindow(WINDOW_SKIN_SETTINGS);
401
402 DestroyWindow(WINDOW_HOME);
403 DestroyWindow(WINDOW_PROGRAMS);
404 DestroyWindow(WINDOW_PICTURES);
405 DestroyWindow(WINDOW_WEATHER);
406 DestroyWindow(WINDOW_DIALOG_GAME_CONTROLLERS);
407 DestroyWindow(WINDOW_GAMES);
408 DestroyWindow(WINDOW_DIALOG_GAME_OSD);
409 DestroyWindow(WINDOW_DIALOG_GAME_VIDEO_FILTER);
410 DestroyWindow(WINDOW_DIALOG_GAME_STRETCH_MODE);
411 DestroyWindow(WINDOW_DIALOG_GAME_VOLUME);
412 DestroyWindow(WINDOW_DIALOG_GAME_ADVANCED_SETTINGS);
413 DestroyWindow(WINDOW_DIALOG_GAME_VIDEO_ROTATION);
414 DestroyWindow(WINDOW_FULLSCREEN_GAME);
415
416 Remove(WINDOW_SETTINGS_SERVICE);
417 Remove(WINDOW_SETTINGS_MYPVR);
418 Remove(WINDOW_SETTINGS_PLAYER);
419 Remove(WINDOW_SETTINGS_MEDIA);
420 Remove(WINDOW_SETTINGS_INTERFACE);
421 Remove(WINDOW_SETTINGS_MYGAMES);
422 DestroyWindow(WINDOW_SETTINGS_SYSTEM); // all the settings categories
423
424 Remove(WINDOW_DIALOG_KAI_TOAST);
425 Remove(WINDOW_DIALOG_SEEK_BAR);
426 Remove(WINDOW_DIALOG_VOLUME_BAR);
427
428 DestroyWindow(WINDOW_EVENT_LOG);
429
430 DestroyWindow(WINDOW_DIALOG_PERIPHERALS);
431 DestroyWindow(WINDOW_DIALOG_PERIPHERAL_SETTINGS);
432 }
433 catch (...)
434 {
435 CLog::Log(LOGERROR, "Exception in CGUIWindowManager::DestroyWindows()");
436 return false;
437 }
438
439 return true;
440 }
441
DestroyWindow(int id)442 void CGUIWindowManager::DestroyWindow(int id)
443 {
444 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
445 CGUIWindow *pWindow = GetWindow(id);
446 if (pWindow)
447 {
448 Remove(id);
449 pWindow->FreeResources(true);
450 delete pWindow;
451 }
452 }
453
SendMessage(int message,int senderID,int destID,int param1,int param2)454 bool CGUIWindowManager::SendMessage(int message, int senderID, int destID, int param1, int param2)
455 {
456 CGUIMessage msg(message, senderID, destID, param1, param2);
457 return SendMessage(msg);
458 }
459
SendMessage(CGUIMessage & message)460 bool CGUIWindowManager::SendMessage(CGUIMessage& message)
461 {
462 bool handled = false;
463 // CLog::Log(LOGDEBUG,"SendMessage: mess=%d send=%d control=%d param1=%d", message.GetMessage(), message.GetSenderId(), message.GetControlId(), message.GetParam1());
464 // Send the message to all none window targets
465 for (int i = 0; i < int(m_vecMsgTargets.size()); i++)
466 {
467 IMsgTargetCallback* pMsgTarget = m_vecMsgTargets[i];
468
469 if (pMsgTarget)
470 {
471 if (pMsgTarget->OnMessage( message )) handled = true;
472 }
473 }
474
475 // A GUI_MSG_NOTIFY_ALL is send to any active modal dialog
476 // and all windows whether they are active or not
477 if (message.GetMessage()==GUI_MSG_NOTIFY_ALL)
478 {
479 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
480
481 for (auto it = m_activeDialogs.rbegin(); it != m_activeDialogs.rend(); ++it)
482 {
483 (*it)->OnMessage(message);
484 }
485
486 for (const auto& entry : m_mapWindows)
487 {
488 entry.second->OnMessage(message);
489 }
490
491 return true;
492 }
493
494 // Normal messages are sent to:
495 // 1. All active modeless dialogs
496 // 2. The topmost dialog that accepts the message
497 // 3. The underlying window (only if it is the sender or receiver if a modal dialog is active)
498
499 bool hasModalDialog(false);
500 bool modalAcceptedMessage(false);
501 // don't use an iterator for this loop, as some messages mean that m_activeDialogs is altered,
502 // which will invalidate any iterator
503 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
504 size_t topWindow = m_activeDialogs.size();
505 while (topWindow)
506 {
507 CGUIWindow* dialog = m_activeDialogs[--topWindow];
508
509 if (!modalAcceptedMessage && dialog->IsModalDialog())
510 { // modal window
511 hasModalDialog = true;
512 if (!modalAcceptedMessage && dialog->OnMessage( message ))
513 {
514 modalAcceptedMessage = handled = true;
515 }
516 }
517 else if (!dialog->IsModalDialog())
518 { // modeless
519 if (dialog->OnMessage( message ))
520 handled = true;
521 }
522
523 if (topWindow > m_activeDialogs.size())
524 topWindow = m_activeDialogs.size();
525 }
526
527 // now send to the underlying window
528 CGUIWindow* window = GetWindow(GetActiveWindow());
529 if (window)
530 {
531 if (hasModalDialog)
532 {
533 // only send the message to the underlying window if it's the recipient
534 // or sender (or we have no sender)
535 if (message.GetSenderId() == window->GetID() ||
536 message.GetControlId() == window->GetID() ||
537 message.GetSenderId() == 0 )
538 {
539 if (window->OnMessage(message)) handled = true;
540 }
541 }
542 else
543 {
544 if (window->OnMessage(message)) handled = true;
545 }
546 }
547 return handled;
548 }
549
SendMessage(CGUIMessage & message,int window)550 bool CGUIWindowManager::SendMessage(CGUIMessage& message, int window)
551 {
552 if (window == 0)
553 // send to no specified windows.
554 return SendMessage(message);
555 CGUIWindow* pWindow = GetWindow(window);
556 if(pWindow)
557 return pWindow->OnMessage(message);
558 else
559 return false;
560 }
561
AddUniqueInstance(CGUIWindow * window)562 void CGUIWindowManager::AddUniqueInstance(CGUIWindow *window)
563 {
564 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
565 // increment our instance (upper word of windowID)
566 // until we get a window we don't have
567 int instance = 0;
568 while (GetWindow(window->GetID()))
569 window->SetID(window->GetID() + (++instance << 16));
570 Add(window);
571 }
572
Add(CGUIWindow * pWindow)573 void CGUIWindowManager::Add(CGUIWindow* pWindow)
574 {
575 if (!pWindow)
576 {
577 CLog::Log(LOGERROR, "Attempted to add a NULL window pointer to the window manager.");
578 return;
579 }
580 // push back all the windows if there are more than one covered by this class
581 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
582
583 for (int id : pWindow->GetIDRange())
584 {
585 auto it = m_mapWindows.find(id);
586 if (it != m_mapWindows.end())
587 {
588 CLog::Log(LOGERROR, "Error, trying to add a second window with id %u "
589 "to the window manager", id);
590 return;
591 }
592
593 m_mapWindows.insert(std::make_pair(id, pWindow));
594 }
595 }
596
AddCustomWindow(CGUIWindow * pWindow)597 void CGUIWindowManager::AddCustomWindow(CGUIWindow* pWindow)
598 {
599 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
600 Add(pWindow);
601 m_vecCustomWindows.emplace_back(pWindow);
602 }
603
RegisterDialog(CGUIWindow * dialog)604 void CGUIWindowManager::RegisterDialog(CGUIWindow* dialog)
605 {
606 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
607 // only add the window if it does not exists
608 for (const auto& window : m_activeDialogs)
609 {
610 if (window->GetID() == dialog->GetID())
611 return;
612 }
613 m_activeDialogs.emplace_back(dialog);
614 }
615
Remove(int id)616 void CGUIWindowManager::Remove(int id)
617 {
618 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
619
620 auto it = m_mapWindows.find(id);
621 if (it != m_mapWindows.end())
622 {
623 CGUIWindow *window = it->second;
624 m_windowHistory.erase(std::remove_if(m_windowHistory.begin(),
625 m_windowHistory.end(),
626 [id](int winId){ return winId == id; }),
627 m_windowHistory.end());
628 m_activeDialogs.erase(std::remove_if(m_activeDialogs.begin(),
629 m_activeDialogs.end(),
630 [window](CGUIWindow* w){ return w == window; }),
631 m_activeDialogs.end());
632 m_mapWindows.erase(it);
633 }
634 else
635 {
636 CLog::Log(LOGWARNING, "Attempted to remove window %u "
637 "from the window manager when it didn't exist",
638 id);
639 }
640 }
641
642 // removes and deletes the window. Should only be called
643 // from the class that created the window using new.
Delete(int id)644 void CGUIWindowManager::Delete(int id)
645 {
646 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
647 CGUIWindow *pWindow = GetWindow(id);
648 if (pWindow)
649 {
650 Remove(id);
651 m_deleteWindows.emplace_back(pWindow);
652 }
653 }
654
PreviousWindow()655 void CGUIWindowManager::PreviousWindow()
656 {
657 // deactivate any window
658 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
659 CLog::Log(LOGDEBUG,"CGUIWindowManager::PreviousWindow: Deactivate");
660 int currentWindow = GetActiveWindow();
661 CGUIWindow *pCurrentWindow = GetWindow(currentWindow);
662 if (!pCurrentWindow)
663 return; // no windows or window history yet
664
665 // check to see whether our current window has a <previouswindow> tag
666 if (pCurrentWindow->GetPreviousWindow() != WINDOW_INVALID)
667 {
668 //! @todo we may need to test here for the
669 //! whether our history should be changed
670
671 // don't reactivate the previouswindow if it is ourselves.
672 if (currentWindow != pCurrentWindow->GetPreviousWindow())
673 ActivateWindow(pCurrentWindow->GetPreviousWindow());
674 return;
675 }
676 // get the previous window in our stack
677 if (m_windowHistory.size() < 2)
678 {
679 // no previous window history yet - check if we should just activate home
680 if (GetActiveWindow() != WINDOW_INVALID && GetActiveWindow() != WINDOW_HOME)
681 {
682 CloseWindowSync(pCurrentWindow);
683 ClearWindowHistory();
684 ActivateWindow(WINDOW_HOME);
685 }
686 return;
687 }
688 m_windowHistory.pop_back();
689 int previousWindow = GetActiveWindow();
690 m_windowHistory.emplace_back(currentWindow);
691
692 CGUIWindow *pNewWindow = GetWindow(previousWindow);
693 if (!pNewWindow)
694 {
695 CLog::Log(LOGERROR, "Unable to activate the previous window");
696 CloseWindowSync(pCurrentWindow);
697 ClearWindowHistory();
698 ActivateWindow(WINDOW_HOME);
699 return;
700 }
701
702 // ok to go to the previous window now
703
704 // tell our info manager which window we are going to
705 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetGUIControlsInfoProvider().SetNextWindow(previousWindow);
706
707 // deinitialize our window
708 CloseWindowSync(pCurrentWindow);
709
710 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetGUIControlsInfoProvider().SetNextWindow(WINDOW_INVALID);
711 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetGUIControlsInfoProvider().SetPreviousWindow(currentWindow);
712
713 // remove the current window off our window stack
714 m_windowHistory.pop_back();
715
716 // ok, initialize the new window
717 CLog::Log(LOGDEBUG,"CGUIWindowManager::PreviousWindow: Activate new");
718 CGUIMessage msg2(GUI_MSG_WINDOW_INIT, 0, 0, WINDOW_INVALID, GetActiveWindow());
719 pNewWindow->OnMessage(msg2);
720
721 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetGUIControlsInfoProvider().SetPreviousWindow(WINDOW_INVALID);
722 }
723
ChangeActiveWindow(int newWindow,const std::string & strPath)724 void CGUIWindowManager::ChangeActiveWindow(int newWindow, const std::string& strPath)
725 {
726 std::vector<std::string> params;
727 if (!strPath.empty())
728 params.emplace_back(strPath);
729 ActivateWindow(newWindow, params, true);
730 }
731
ActivateWindow(int iWindowID,const std::string & strPath)732 void CGUIWindowManager::ActivateWindow(int iWindowID, const std::string& strPath)
733 {
734 std::vector<std::string> params;
735 if (!strPath.empty())
736 params.emplace_back(strPath);
737 ActivateWindow(iWindowID, params, false);
738 }
739
ForceActivateWindow(int iWindowID,const std::string & strPath)740 void CGUIWindowManager::ForceActivateWindow(int iWindowID, const std::string& strPath)
741 {
742 std::vector<std::string> params;
743 if (!strPath.empty())
744 params.emplace_back(strPath);
745 ActivateWindow(iWindowID, params, false, true);
746 }
747
ActivateWindow(int iWindowID,const std::vector<std::string> & params,bool swappingWindows,bool force)748 void CGUIWindowManager::ActivateWindow(int iWindowID, const std::vector<std::string>& params, bool swappingWindows /* = false */, bool force /* = false */)
749 {
750 if (!g_application.IsCurrentThread())
751 {
752 // make sure graphics lock is not held
753 CSingleExit leaveIt(CServiceBroker::GetWinSystem()->GetGfxContext());
754 CApplicationMessenger::GetInstance().SendMsg(TMSG_GUI_ACTIVATE_WINDOW, iWindowID, swappingWindows ? 1 : 0, nullptr, "", params);
755 }
756 else
757 {
758 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
759 ActivateWindow_Internal(iWindowID, params, swappingWindows, force);
760 }
761 }
762
ActivateWindow_Internal(int iWindowID,const std::vector<std::string> & params,bool swappingWindows,bool force)763 void CGUIWindowManager::ActivateWindow_Internal(int iWindowID, const std::vector<std::string>& params, bool swappingWindows, bool force /* = false */)
764 {
765 // translate virtual windows
766 if (iWindowID == WINDOW_START)
767 { // virtual start window
768 iWindowID = g_SkinInfo->GetStartWindow();
769 }
770
771 // debug
772 CLog::Log(LOGDEBUG, "Activating window ID: %i", iWindowID);
773
774 // make sure we check mediasources from home
775 if (GetActiveWindow() == WINDOW_HOME)
776 {
777 g_passwordManager.SetMediaSourcePath(!params.empty() ? params[0] : "");
778 }
779 else
780 {
781 g_passwordManager.SetMediaSourcePath("");
782 }
783
784 if (!g_passwordManager.CheckMenuLock(iWindowID))
785 {
786 CLog::Log(LOGERROR,
787 "MasterCode or MediaSource-code is wrong: Window with id {} will not be loaded! "
788 "Enter a correct code!",
789 iWindowID);
790 if (GetActiveWindow() == WINDOW_INVALID && iWindowID != WINDOW_HOME)
791 ActivateWindow(WINDOW_HOME);
792 return;
793 }
794
795 // first check existence of the window we wish to activate.
796 CGUIWindow *pNewWindow = GetWindow(iWindowID);
797 if (!pNewWindow)
798 { // nothing to see here - move along
799 CLog::Log(LOGERROR, "Unable to locate window with id %d. Check skin files", iWindowID - WINDOW_HOME);
800 if (IsWindowActive(WINDOW_STARTUP_ANIM))
801 ActivateWindow(WINDOW_HOME);
802 return ;
803 }
804 else if (!pNewWindow->CanBeActivated())
805 {
806 if (IsWindowActive(WINDOW_STARTUP_ANIM))
807 ActivateWindow(WINDOW_HOME);
808 return;
809 }
810 else if (pNewWindow->IsDialog())
811 { // if we have a dialog, we do a DoModal() rather than activate the window
812 if (!pNewWindow->IsDialogRunning())
813 {
814 CSingleExit exitit(CServiceBroker::GetWinSystem()->GetGfxContext());
815 static_cast<CGUIDialog *>(pNewWindow)->Open(params.size() > 0 ? params[0] : "");
816 // Invalidate underlying windows after closing a modal dialog
817 MarkDirty();
818 }
819 return;
820 }
821
822 // don't activate a window if there are active modal dialogs of type MODAL
823 if (!force && HasModalDialog(true))
824 {
825 CLog::Log(LOGINFO, "Activate of window '%i' refused because there are active modal dialogs", iWindowID);
826 CServiceBroker::GetGUI()->GetAudioManager().PlayActionSound(CAction(ACTION_ERROR));
827 return;
828 }
829
830 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetGUIControlsInfoProvider().SetNextWindow(iWindowID);
831
832 // deactivate any window
833 int currentWindow = GetActiveWindow();
834 CGUIWindow *pWindow = GetWindow(currentWindow);
835 if (pWindow)
836 CloseWindowSync(pWindow, iWindowID);
837 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetGUIControlsInfoProvider().SetNextWindow(WINDOW_INVALID);
838
839 // Add window to the history list (we must do this before we activate it,
840 // as all messages done in WINDOW_INIT will want to be sent to the new
841 // topmost window). If we are swapping windows, we pop the old window
842 // off the history stack
843 if (swappingWindows && !m_windowHistory.empty())
844 m_windowHistory.pop_back();
845 AddToWindowHistory(iWindowID);
846
847 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetGUIControlsInfoProvider().SetPreviousWindow(currentWindow);
848 // Send the init message
849 CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0, 0, currentWindow, iWindowID);
850 msg.SetStringParams(params);
851 pNewWindow->OnMessage(msg);
852 // CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetGUIControlsInfoProvider().SetPreviousWindow(WINDOW_INVALID);
853 }
854
CloseDialogs(bool forceClose) const855 void CGUIWindowManager::CloseDialogs(bool forceClose) const
856 {
857 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
858
859 //This is to avoid an assert about out of bounds iterator
860 //when m_activeDialogs happens to be empty
861 if (m_activeDialogs.empty())
862 return;
863
864 auto activeDialogs = m_activeDialogs;
865 for (const auto& window : activeDialogs)
866 {
867 if (window->IsModalDialog())
868 window->Close(forceClose);
869 }
870 }
871
CloseInternalModalDialogs(bool forceClose) const872 void CGUIWindowManager::CloseInternalModalDialogs(bool forceClose) const
873 {
874 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
875 if (m_activeDialogs.empty())
876 return;
877
878 auto activeDialogs = m_activeDialogs;
879 for (const auto& window : activeDialogs)
880 {
881 if (window->IsModalDialog() && !IsAddonWindow(window->GetID()) && !IsPythonWindow(window->GetID()))
882 window->Close(forceClose);
883 }
884 }
885
OnApplicationMessage(ThreadMessage * pMsg)886 void CGUIWindowManager::OnApplicationMessage(ThreadMessage* pMsg)
887 {
888 switch (pMsg->dwMessage)
889 {
890 case TMSG_GUI_DIALOG_OPEN:
891 {
892 if (pMsg->lpVoid)
893 static_cast<CGUIDialog*>(pMsg->lpVoid)->Open(pMsg->param2, pMsg->strParam);
894 else
895 {
896 CGUIDialog* pDialog = static_cast<CGUIDialog*>(GetWindow(pMsg->param1));
897 if (pDialog)
898 pDialog->Open(pMsg->strParam);
899 }
900 }
901 break;
902
903 case TMSG_GUI_WINDOW_CLOSE:
904 {
905 CGUIWindow *window = static_cast<CGUIWindow *>(pMsg->lpVoid);
906 if (window)
907 window->Close((pMsg->param1 & 0x1) ? true : false, pMsg->param1, (pMsg->param1 & 0x2) ? true : false);
908 }
909 break;
910
911 case TMSG_GUI_ACTIVATE_WINDOW:
912 {
913 ActivateWindow(pMsg->param1, pMsg->params, pMsg->param2 > 0);
914 }
915 break;
916
917 case TMSG_GUI_PREVIOUS_WINDOW:
918 {
919 PreviousWindow();
920 }
921 break;
922
923 case TMSG_GUI_ADDON_DIALOG:
924 {
925 if (pMsg->lpVoid)
926 {
927 static_cast<ADDON::CGUIAddonWindowDialog*>(pMsg->lpVoid)->Show_Internal(pMsg->param2 > 0);
928 }
929 }
930 break;
931
932 #ifdef HAS_PYTHON
933 case TMSG_GUI_PYTHON_DIALOG:
934 {
935 // This hack is not much better but at least I don't need to make ApplicationMessenger
936 // know about Addon (Python) specific classes.
937 CAction caction(pMsg->param1);
938 static_cast<CGUIWindow*>(pMsg->lpVoid)->OnAction(caction);
939 }
940 break;
941 #endif
942
943 case TMSG_GUI_ACTION:
944 {
945 if (pMsg->lpVoid)
946 {
947 CAction *action = static_cast<CAction *>(pMsg->lpVoid);
948 if (pMsg->param1 == WINDOW_INVALID)
949 g_application.OnAction(*action);
950 else
951 {
952 CGUIWindow *pWindow = GetWindow(pMsg->param1);
953 if (pWindow)
954 pWindow->OnAction(*action);
955 else
956 CLog::Log(LOGWARNING, "Failed to get window with ID %i to send an action to", pMsg->param1);
957 }
958 delete action;
959 }
960 }
961 break;
962
963 case TMSG_GUI_MESSAGE:
964 if (pMsg->lpVoid)
965 {
966 CGUIMessage *message = static_cast<CGUIMessage *>(pMsg->lpVoid);
967 SendMessage(*message, pMsg->param1);
968 delete message;
969 }
970 break;
971
972 case TMSG_GUI_DIALOG_YESNO:
973 {
974
975 if (!pMsg->lpVoid && pMsg->param1 < 0 && pMsg->param2 < 0)
976 return;
977
978 auto dialog = static_cast<CGUIDialogYesNo*>(GetWindow(WINDOW_DIALOG_YES_NO));
979 if (!dialog)
980 return;
981
982 if (pMsg->lpVoid)
983 pMsg->SetResult(dialog->ShowAndGetInput(*static_cast<HELPERS::DialogYesNoMessage*>(pMsg->lpVoid)));
984 else
985 {
986 HELPERS::DialogYesNoMessage options;
987 options.heading = pMsg->param1;
988 options.text = pMsg->param2;
989 pMsg->SetResult(dialog->ShowAndGetInput(options));
990 }
991
992 }
993 break;
994
995 case TMSG_GUI_DIALOG_OK:
996 {
997
998 if (!pMsg->lpVoid && pMsg->param1 < 0 && pMsg->param2 < 0)
999 return;
1000
1001 auto dialogOK = static_cast<CGUIDialogOK*>(GetWindow(WINDOW_DIALOG_OK));
1002 if (!dialogOK)
1003 return;
1004
1005 if (pMsg->lpVoid)
1006 dialogOK->ShowAndGetInput(*static_cast<HELPERS::DialogOKMessage*>(pMsg->lpVoid));
1007 else
1008 {
1009 HELPERS::DialogOKMessage options;
1010 options.heading = pMsg->param1;
1011 options.text = pMsg->param2;
1012 dialogOK->ShowAndGetInput(options);
1013 }
1014 pMsg->SetResult(static_cast<int>(dialogOK->IsConfirmed()));
1015 }
1016 break;
1017 }
1018 }
1019
GetMessageMask()1020 int CGUIWindowManager::GetMessageMask()
1021 {
1022 return TMSG_MASK_WINDOWMANAGER;
1023 }
1024
OnAction(const CAction & action) const1025 bool CGUIWindowManager::OnAction(const CAction &action) const
1026 {
1027 auto actionId = action.GetID();
1028 if (actionId == ACTION_GESTURE_BEGIN)
1029 {
1030 m_touchGestureActive = true;
1031 }
1032
1033 bool ret;
1034 if (!m_inhibitTouchGestureEvents || !action.IsGesture())
1035 {
1036 ret = HandleAction(action);
1037 }
1038 else
1039 {
1040 // We swallow the event, so it is handled
1041 ret = true;
1042 CLog::Log(LOGDEBUG, "Swallowing touch action %d due to inhibition on window switch", actionId);
1043 }
1044
1045 if (actionId == ACTION_GESTURE_END || actionId == ACTION_GESTURE_ABORT)
1046 {
1047 m_touchGestureActive = false;
1048 m_inhibitTouchGestureEvents = false;
1049 }
1050
1051 return ret;
1052 }
1053
HandleAction(CAction const & action) const1054 bool CGUIWindowManager::HandleAction(CAction const& action) const
1055 {
1056 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1057 size_t topmost = m_activeDialogs.size();
1058 while (topmost)
1059 {
1060 CGUIWindow *dialog = m_activeDialogs[--topmost];
1061 lock.Leave();
1062 if (dialog->IsModalDialog())
1063 { // we have the topmost modal dialog
1064 if (!dialog->IsAnimating(ANIM_TYPE_WINDOW_CLOSE))
1065 {
1066 bool fallThrough = (dialog->GetID() == WINDOW_DIALOG_FULLSCREEN_INFO);
1067 if (dialog->OnAction(action))
1068 return true;
1069 // dialog didn't want the action - we'd normally return false
1070 // but for some dialogs we want to drop the actions through
1071 if (fallThrough)
1072 break;
1073 return false;
1074 }
1075 CLog::Log(LOGWARNING, "CGUIWindowManager - %s - ignoring action %i, because topmost modal dialog closing animation is running",
1076 __FUNCTION__, action.GetID());
1077 return true; // do nothing with the action until the anim is finished
1078 }
1079 lock.Enter();
1080 if (topmost > m_activeDialogs.size())
1081 topmost = m_activeDialogs.size();
1082 }
1083 lock.Leave();
1084 CGUIWindow* window = GetWindow(GetActiveWindow());
1085 if (window)
1086 return window->OnAction(action);
1087 return false;
1088 }
1089
RenderOrderSortFunction(CGUIWindow * first,CGUIWindow * second)1090 bool RenderOrderSortFunction(CGUIWindow *first, CGUIWindow *second)
1091 {
1092 return first->GetRenderOrder() < second->GetRenderOrder();
1093 }
1094
Process(unsigned int currentTime)1095 void CGUIWindowManager::Process(unsigned int currentTime)
1096 {
1097 assert(g_application.IsCurrentThread());
1098 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1099
1100 m_dirtyregions.clear();
1101
1102 CGUIWindow* pWindow = GetWindow(GetActiveWindow());
1103 if (pWindow)
1104 pWindow->DoProcess(currentTime, m_dirtyregions);
1105
1106 // process all dialogs - visibility may change etc.
1107 for (const auto& entry : m_mapWindows)
1108 {
1109 CGUIWindow *pWindow = entry.second;
1110 if (pWindow && pWindow->IsDialog())
1111 pWindow->DoProcess(currentTime, m_dirtyregions);
1112 }
1113
1114 for (auto& itr : m_dirtyregions)
1115 m_tracker.MarkDirtyRegion(itr);
1116 }
1117
MarkDirty()1118 void CGUIWindowManager::MarkDirty()
1119 {
1120 MarkDirty(CRect(0, 0, float(CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth()), float(CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight())));
1121 }
1122
MarkDirty(const CRect & rect)1123 void CGUIWindowManager::MarkDirty(const CRect& rect)
1124 {
1125 m_tracker.MarkDirtyRegion(CDirtyRegion(rect));
1126
1127 CGUIWindow* pWindow = GetWindow(GetActiveWindow());
1128 if (pWindow)
1129 pWindow->MarkDirtyRegion();
1130
1131 // make copy of vector as we may remove items from it as we go
1132 auto activeDialogs = m_activeDialogs;
1133 for (const auto& window : activeDialogs)
1134 if (window->IsDialogRunning())
1135 window->MarkDirtyRegion();
1136 }
1137
RenderPass() const1138 void CGUIWindowManager::RenderPass() const
1139 {
1140 CGUIWindow* pWindow = GetWindow(GetActiveWindow());
1141 if (pWindow)
1142 {
1143 pWindow->ClearBackground();
1144 pWindow->DoRender();
1145 }
1146
1147 // we render the dialogs based on their render order.
1148 auto renderList = m_activeDialogs;
1149 stable_sort(renderList.begin(), renderList.end(), RenderOrderSortFunction);
1150
1151 for (const auto& window : renderList)
1152 {
1153 if (window->IsDialogRunning())
1154 window->DoRender();
1155 }
1156 }
1157
RenderEx() const1158 void CGUIWindowManager::RenderEx() const
1159 {
1160 CGUIWindow* pWindow = GetWindow(GetActiveWindow());
1161 if (pWindow)
1162 pWindow->RenderEx();
1163
1164 // We don't call RenderEx for now on dialogs since it is used
1165 // to trigger non gui video rendering. We can activate it later at any time.
1166 /*
1167 vector<CGUIWindow *> &activeDialogs = m_activeDialogs;
1168 for (iDialog it = activeDialogs.begin(); it != activeDialogs.end(); ++it)
1169 {
1170 if ((*it)->IsDialogRunning())
1171 (*it)->RenderEx();
1172 }
1173 */
1174 }
1175
Render()1176 bool CGUIWindowManager::Render()
1177 {
1178 assert(g_application.IsCurrentThread());
1179 CSingleExit lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1180
1181 CDirtyRegionList dirtyRegions = m_tracker.GetDirtyRegions();
1182
1183 bool hasRendered = false;
1184 // If we visualize the regions we will always render the entire viewport
1185 if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_guiVisualizeDirtyRegions || CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_FILL_VIEWPORT_ALWAYS)
1186 {
1187 RenderPass();
1188 hasRendered = true;
1189 }
1190 else if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_FILL_VIEWPORT_ON_CHANGE)
1191 {
1192 if (!dirtyRegions.empty())
1193 {
1194 RenderPass();
1195 hasRendered = true;
1196 }
1197 }
1198 else
1199 {
1200 for (const auto& i : dirtyRegions)
1201 {
1202 if (i.IsEmpty())
1203 continue;
1204
1205 CServiceBroker::GetWinSystem()->GetGfxContext().SetScissors(i);
1206 RenderPass();
1207 hasRendered = true;
1208 }
1209 CServiceBroker::GetWinSystem()->GetGfxContext().ResetScissors();
1210 }
1211
1212 if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_guiVisualizeDirtyRegions)
1213 {
1214 CServiceBroker::GetWinSystem()->GetGfxContext().SetRenderingResolution(CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo(), false);
1215 const CDirtyRegionList &markedRegions = m_tracker.GetMarkedRegions();
1216 for (const auto& i : markedRegions)
1217 CGUITexture::DrawQuad(i, 0x0fff0000);
1218 for (const auto& i : dirtyRegions)
1219 CGUITexture::DrawQuad(i, 0x4c00ff00);
1220 }
1221
1222 return hasRendered;
1223 }
1224
AfterRender()1225 void CGUIWindowManager::AfterRender()
1226 {
1227 m_tracker.CleanMarkedRegions();
1228
1229 CGUIWindow* pWindow = GetWindow(GetActiveWindow());
1230 if (pWindow)
1231 pWindow->AfterRender();
1232
1233 // make copy of vector as we may remove items from it as we go
1234 auto activeDialogs = m_activeDialogs;
1235 for (const auto& window : activeDialogs)
1236 {
1237 if (window->IsDialogRunning())
1238 {
1239 window->AfterRender();
1240 // Dialog state can affect visibility states
1241 if (pWindow && window->IsControlDirty())
1242 pWindow->MarkDirtyRegion();
1243 }
1244 }
1245 }
1246
FrameMove()1247 void CGUIWindowManager::FrameMove()
1248 {
1249 assert(g_application.IsCurrentThread());
1250 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1251
1252 if(m_iNested == 0)
1253 {
1254 // delete any windows queued for deletion
1255 for (const auto& window : m_deleteWindows)
1256 {
1257 // Free any window resources
1258 window->FreeResources(true);
1259 delete window;
1260 }
1261 m_deleteWindows.clear();
1262 }
1263
1264 CGUIWindow* pWindow = GetWindow(GetActiveWindow());
1265 if (pWindow)
1266 pWindow->FrameMove();
1267 // update any dialogs - we take a copy of the vector as some dialogs may close themselves
1268 // during this call
1269 auto dialogs = m_activeDialogs;
1270 for (const auto& window : dialogs)
1271 {
1272 window->FrameMove();
1273 }
1274
1275 CServiceBroker::GetGUI()->GetInfoManager().UpdateAVInfo();
1276 }
1277
GetDialog(int id) const1278 CGUIDialog* CGUIWindowManager::GetDialog(int id) const
1279 {
1280 CGUIWindow *window = GetWindow(id);
1281 if (window && window->IsDialog())
1282 return dynamic_cast<CGUIDialog*>(window);
1283 return nullptr;
1284 }
1285
GetWindow(int id) const1286 CGUIWindow* CGUIWindowManager::GetWindow(int id) const
1287 {
1288 if (id == 0 || id == WINDOW_INVALID)
1289 return nullptr;
1290
1291 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1292
1293 auto it = m_mapWindows.find(id);
1294 if (it != m_mapWindows.end())
1295 return it->second;
1296 return nullptr;
1297 }
1298
ProcessRenderLoop(bool renderOnly)1299 bool CGUIWindowManager::ProcessRenderLoop(bool renderOnly)
1300 {
1301 bool renderGui = true;
1302
1303 if (g_application.IsCurrentThread() && m_pCallback)
1304 {
1305 renderGui = m_pCallback->GetRenderGUI();
1306 m_iNested++;
1307 if (!renderOnly)
1308 m_pCallback->Process();
1309 m_pCallback->FrameMove(!renderOnly);
1310 m_pCallback->Render();
1311 m_iNested--;
1312 }
1313 if (g_application.m_bStop || !renderGui)
1314 return false;
1315 else
1316 return true;
1317 }
1318
SetCallback(IWindowManagerCallback & callback)1319 void CGUIWindowManager::SetCallback(IWindowManagerCallback& callback)
1320 {
1321 m_pCallback = &callback;
1322 }
1323
DeInitialize()1324 void CGUIWindowManager::DeInitialize()
1325 {
1326 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1327
1328 // Need a copy bacause addon-dialogs remove itself on Close()
1329 std::unordered_map<int, CGUIWindow*> closeMap(m_mapWindows);
1330 for (const auto& entry : closeMap)
1331 {
1332 CGUIWindow* pWindow = entry.second;
1333 if (IsWindowActive(entry.first, false))
1334 {
1335 pWindow->DisableAnimations();
1336 pWindow->Close(true);
1337 }
1338 pWindow->ResetControlStates();
1339 pWindow->FreeResources(true);
1340 }
1341 UnloadNotOnDemandWindows();
1342
1343 m_vecMsgTargets.erase( m_vecMsgTargets.begin(), m_vecMsgTargets.end() );
1344
1345 // destroy our custom windows...
1346 for (int i = 0; i < int(m_vecCustomWindows.size()); i++)
1347 {
1348 CGUIWindow *pWindow = m_vecCustomWindows[i];
1349 RemoveFromWindowHistory(pWindow->GetID());
1350 Remove(pWindow->GetID());
1351 delete pWindow;
1352 }
1353
1354 // clear our vectors of windows
1355 m_vecCustomWindows.clear();
1356 m_activeDialogs.clear();
1357
1358 m_initialized = false;
1359 }
1360
1361 /// \brief Unroute window
1362 /// \param id ID of the window routed
RemoveDialog(int id)1363 void CGUIWindowManager::RemoveDialog(int id)
1364 {
1365 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1366 m_activeDialogs.erase(std::remove_if(m_activeDialogs.begin(),
1367 m_activeDialogs.end(),
1368 [id](CGUIWindow* dialog) { return dialog->GetID() == id; }),
1369 m_activeDialogs.end());
1370 }
1371
HasModalDialog(bool ignoreClosing) const1372 bool CGUIWindowManager::HasModalDialog(bool ignoreClosing) const
1373 {
1374 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1375 for (const auto& window : m_activeDialogs)
1376 {
1377 if (window->IsDialog() &&
1378 window->IsModalDialog() &&
1379 (!ignoreClosing || !window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE)))
1380 {
1381 return true;
1382 }
1383 }
1384 return false;
1385 }
1386
HasVisibleModalDialog() const1387 bool CGUIWindowManager::HasVisibleModalDialog() const
1388 {
1389 return HasModalDialog(false);
1390 }
1391
GetTopmostDialog(bool modal,bool ignoreClosing) const1392 int CGUIWindowManager::GetTopmostDialog(bool modal, bool ignoreClosing) const
1393 {
1394 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1395 for (auto it = m_activeDialogs.rbegin(); it != m_activeDialogs.rend(); ++it)
1396 {
1397 CGUIWindow *dialog = *it;
1398 if ((!modal || dialog->IsModalDialog()) && (!ignoreClosing || !dialog->IsAnimating(ANIM_TYPE_WINDOW_CLOSE)))
1399 return dialog->GetID();
1400 }
1401 return WINDOW_INVALID;
1402 }
1403
GetTopmostDialog(bool ignoreClosing) const1404 int CGUIWindowManager::GetTopmostDialog(bool ignoreClosing /*= false*/) const
1405 {
1406 return GetTopmostDialog(false, ignoreClosing);
1407 }
1408
GetTopmostModalDialog(bool ignoreClosing) const1409 int CGUIWindowManager::GetTopmostModalDialog(bool ignoreClosing /*= false*/) const
1410 {
1411 return GetTopmostDialog(true, ignoreClosing);
1412 }
1413
SendThreadMessage(CGUIMessage & message,int window)1414 void CGUIWindowManager::SendThreadMessage(CGUIMessage& message, int window /*= 0*/)
1415 {
1416 CSingleLock lock(m_critSection);
1417
1418 CGUIMessage* msg = new CGUIMessage(message);
1419 m_vecThreadMessages.emplace_back(std::pair<CGUIMessage*, int>(msg,window));
1420 }
1421
DispatchThreadMessages()1422 void CGUIWindowManager::DispatchThreadMessages()
1423 {
1424 // This method only be called in the xbmc main thread.
1425
1426 // XXX: for more info of this method
1427 // check the pr here: https://github.com/xbmc/xbmc/pull/2253
1428
1429 // As a thread message queue service, it should follow these rules:
1430 // 1. [Must] Thread safe, message can be pushed into queue in arbitrary thread context.
1431 // 2. Messages [must] be processed in dispatch message thread context with the same
1432 // order as they be pushed into the queue.
1433 // 3. Dispatch function [must] support call itself during message process procedure,
1434 // and do not break other rules listed here. to make it clear: in the
1435 // SendMessage(), it could start another xbmc main thread loop, calling
1436 // DispatchThreadMessages() in it's internal loop, this must be supported.
1437 // 4. During DispatchThreadMessages() processing, any new pushed message [should] not
1438 // be processed by the current loop in DispatchThreadMessages(), prevent dead loop.
1439 // 5. If possible, queued messages can be removed by certain filter condition
1440 // and not break above.
1441
1442 CSingleLock lock(m_critSection);
1443
1444 while (!m_vecThreadMessages.empty())
1445 {
1446 // pop up one message per time to make messages be processed by order.
1447 // this will ensure rule No.2 & No.3
1448 CGUIMessage *pMsg = m_vecThreadMessages.front().first;
1449 int window = m_vecThreadMessages.front().second;
1450 m_vecThreadMessages.pop_front();
1451
1452 lock.Leave();
1453
1454 // XXX: during SendMessage(), there could be a deeper 'xbmc main loop' inited by e.g. doModal
1455 // which may loop there and callback to DispatchThreadMessages() multiple times.
1456 if (window)
1457 SendMessage( *pMsg, window );
1458 else
1459 SendMessage( *pMsg );
1460 delete pMsg;
1461
1462 lock.Enter();
1463 }
1464 }
1465
RemoveThreadMessageByMessageIds(int * pMessageIDList)1466 int CGUIWindowManager::RemoveThreadMessageByMessageIds(int *pMessageIDList)
1467 {
1468 CSingleLock lock(m_critSection);
1469 int removedMsgCount = 0;
1470 for (std::list < std::pair<CGUIMessage*,int> >::iterator it = m_vecThreadMessages.begin();
1471 it != m_vecThreadMessages.end();)
1472 {
1473 CGUIMessage *pMsg = it->first;
1474 int *pMsgID;
1475 for(pMsgID = pMessageIDList; *pMsgID != 0; ++pMsgID)
1476 if (pMsg->GetMessage() == *pMsgID)
1477 break;
1478 if (*pMsgID)
1479 {
1480 it = m_vecThreadMessages.erase(it);
1481 delete pMsg;
1482 ++removedMsgCount;
1483 }
1484 else
1485 {
1486 ++it;
1487 }
1488 }
1489 return removedMsgCount;
1490 }
1491
AddMsgTarget(IMsgTargetCallback * pMsgTarget)1492 void CGUIWindowManager::AddMsgTarget(IMsgTargetCallback* pMsgTarget)
1493 {
1494 m_vecMsgTargets.emplace_back(pMsgTarget);
1495 }
1496
GetActiveWindow() const1497 int CGUIWindowManager::GetActiveWindow() const
1498 {
1499 if (!m_windowHistory.empty())
1500 return m_windowHistory.back();
1501 return WINDOW_INVALID;
1502 }
1503
GetActiveWindowOrDialog() const1504 int CGUIWindowManager::GetActiveWindowOrDialog() const
1505 {
1506 // if there is a dialog active get the dialog id instead
1507 int iWin = GetTopmostModalDialog() & WINDOW_ID_MASK;
1508 if (iWin != WINDOW_INVALID)
1509 return iWin;
1510
1511 // get the currently active window
1512 return GetActiveWindow() & WINDOW_ID_MASK;
1513 }
1514
IsWindowActive(int id,bool ignoreClosing) const1515 bool CGUIWindowManager::IsWindowActive(int id, bool ignoreClosing /* = true */) const
1516 {
1517 // mask out multiple instances of the same window
1518 id &= WINDOW_ID_MASK;
1519 if ((GetActiveWindow() & WINDOW_ID_MASK) == id)
1520 return true;
1521 // run through the dialogs
1522 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1523 for (const auto& window : m_activeDialogs)
1524 {
1525 if ((window->GetID() & WINDOW_ID_MASK) == id && (!ignoreClosing || !window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE)))
1526 return true;
1527 }
1528 return false; // window isn't active
1529 }
1530
IsWindowActive(const std::string & xmlFile,bool ignoreClosing) const1531 bool CGUIWindowManager::IsWindowActive(const std::string &xmlFile, bool ignoreClosing /* = true */) const
1532 {
1533 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1534 CGUIWindow *window = GetWindow(GetActiveWindow());
1535 if (window && StringUtils::EqualsNoCase(URIUtils::GetFileName(window->GetProperty("xmlfile").asString()), xmlFile))
1536 return true;
1537 // run through the dialogs
1538 for (const auto& window : m_activeDialogs)
1539 {
1540 if (StringUtils::EqualsNoCase(URIUtils::GetFileName(window->GetProperty("xmlfile").asString()), xmlFile) &&
1541 (!ignoreClosing || !window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE)))
1542 return true;
1543 }
1544 return false; // window isn't active
1545 }
1546
IsWindowVisible(int id) const1547 bool CGUIWindowManager::IsWindowVisible(int id) const
1548 {
1549 return IsWindowActive(id, false);
1550 }
1551
IsWindowVisible(const std::string & xmlFile) const1552 bool CGUIWindowManager::IsWindowVisible(const std::string &xmlFile) const
1553 {
1554 return IsWindowActive(xmlFile, false);
1555 }
1556
LoadNotOnDemandWindows()1557 void CGUIWindowManager::LoadNotOnDemandWindows()
1558 {
1559 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1560 for (const auto& entry : m_mapWindows)
1561 {
1562 CGUIWindow *pWindow = entry.second;
1563 if (pWindow->GetLoadType() == CGUIWindow::LOAD_ON_GUI_INIT)
1564 {
1565 pWindow->FreeResources(true);
1566 pWindow->Initialize();
1567 }
1568 }
1569 }
1570
UnloadNotOnDemandWindows()1571 void CGUIWindowManager::UnloadNotOnDemandWindows()
1572 {
1573 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1574 for (const auto& entry : m_mapWindows)
1575 {
1576 CGUIWindow *pWindow = entry.second;
1577 if (pWindow->GetLoadType() == CGUIWindow::LOAD_ON_GUI_INIT ||
1578 pWindow->GetLoadType() == CGUIWindow::KEEP_IN_MEMORY)
1579 {
1580 pWindow->FreeResources(true);
1581 }
1582 }
1583 }
1584
AddToWindowHistory(int newWindowID)1585 void CGUIWindowManager::AddToWindowHistory(int newWindowID)
1586 {
1587 // Check the window stack to see if this window is in our history,
1588 // and if so, pop all the other windows off the stack so that we
1589 // always have a predictable "Back" behaviour for each window
1590 std::deque<int> history = m_windowHistory;
1591 while (!history.empty())
1592 {
1593 if (history.back() == newWindowID)
1594 break;
1595 history.pop_back();
1596 }
1597 if (!history.empty())
1598 { // found window in history
1599 m_windowHistory.swap(history);
1600 }
1601 else
1602 {
1603 // didn't find window in history - add it to the stack
1604 m_windowHistory.emplace_back(newWindowID);
1605 }
1606 }
1607
RemoveFromWindowHistory(int windowID)1608 void CGUIWindowManager::RemoveFromWindowHistory(int windowID)
1609 {
1610 std::deque<int> history = m_windowHistory;
1611
1612 // pop windows from stack until we found the window
1613 while (!history.empty())
1614 {
1615 if (history.back() == windowID)
1616 break;
1617 history.pop_back();
1618 }
1619
1620 // found window in history
1621 if (!history.empty())
1622 {
1623 history.pop_back(); // remove window from stack
1624 m_windowHistory.swap(history);
1625 }
1626 }
1627
IsModalDialogTopmost(int id) const1628 bool CGUIWindowManager::IsModalDialogTopmost(int id) const
1629 {
1630 return IsDialogTopmost(id, true);
1631 }
1632
IsModalDialogTopmost(const std::string & xmlFile) const1633 bool CGUIWindowManager::IsModalDialogTopmost(const std::string &xmlFile) const
1634 {
1635 return IsDialogTopmost(xmlFile, true);
1636 }
1637
IsDialogTopmost(int id,bool modal) const1638 bool CGUIWindowManager::IsDialogTopmost(int id, bool modal /* = false */) const
1639 {
1640 CGUIWindow *topmost = GetWindow(GetTopmostDialog(modal, false));
1641 if (topmost && (topmost->GetID() & WINDOW_ID_MASK) == id)
1642 return true;
1643 return false;
1644 }
1645
IsDialogTopmost(const std::string & xmlFile,bool modal) const1646 bool CGUIWindowManager::IsDialogTopmost(const std::string &xmlFile, bool modal /* = false */) const
1647 {
1648 CGUIWindow *topmost = GetWindow(GetTopmostDialog(modal, false));
1649 if (topmost && StringUtils::EqualsNoCase(URIUtils::GetFileName(topmost->GetProperty("xmlfile").asString()), xmlFile))
1650 return true;
1651 return false;
1652 }
1653
HasVisibleControls()1654 bool CGUIWindowManager::HasVisibleControls()
1655 {
1656 CSingleExit lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1657
1658 if (m_activeDialogs.empty())
1659 {
1660 CGUIWindow *window(GetWindow(GetActiveWindow()));
1661 return !window || window->HasVisibleControls();
1662 }
1663 else
1664 return true;
1665 }
1666
ClearWindowHistory()1667 void CGUIWindowManager::ClearWindowHistory()
1668 {
1669 while (!m_windowHistory.empty())
1670 m_windowHistory.pop_back();
1671 }
1672
CloseWindowSync(CGUIWindow * window,int nextWindowID)1673 void CGUIWindowManager::CloseWindowSync(CGUIWindow *window, int nextWindowID /*= 0*/)
1674 {
1675 // Abort touch action if active
1676 if (m_touchGestureActive && !m_inhibitTouchGestureEvents)
1677 {
1678 CLog::Log(LOGDEBUG, "Closing window %d with active touch gesture, sending gesture abort event", window->GetID());
1679 window->OnAction({ACTION_GESTURE_ABORT});
1680 // Don't send any mid-gesture events to next window until new touch starts
1681 m_inhibitTouchGestureEvents = true;
1682 }
1683
1684 window->Close(false, nextWindowID);
1685
1686 bool renderLoopProcessed = true;
1687 while (window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE) && renderLoopProcessed)
1688 renderLoopProcessed = ProcessRenderLoop(true);
1689 }
1690
1691 #ifdef _DEBUG
DumpTextureUse()1692 void CGUIWindowManager::DumpTextureUse()
1693 {
1694 CGUIWindow* pWindow = GetWindow(GetActiveWindow());
1695 if (pWindow)
1696 pWindow->DumpTextureUse();
1697
1698 CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
1699 for (const auto& window : m_activeDialogs)
1700 {
1701 if (window->IsDialogRunning())
1702 window->DumpTextureUse();
1703 }
1704 }
1705 #endif
1706