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