2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "GUIWindowManager.h"
22 #include "GUIAudioManager.h"
23 #include "GUIDialog.h"
24 #include "Application.h"
25 #include "ApplicationMessenger.h"
26 #include "GUIPassword.h"
27 #include "GUIInfoManager.h"
28 #include "threads/SingleLock.h"
29 #include "utils/URIUtils.h"
30 #include "settings/AdvancedSettings.h"
31 #include "settings/Settings.h"
32 #include "addons/Skin.h"
33 #include "GUITexture.h"
34 #include "windowing/WindowingFactory.h"
35 #include "utils/Variant.h"
40 CGUIWindowManager::CGUIWindowManager(void)
43 m_bShowOverlay = true;
45 m_initialized = false;
48 CGUIWindowManager::~CGUIWindowManager(void)
52 void CGUIWindowManager::Initialize()
54 m_tracker.SelectAlgorithm();
57 LoadNotOnDemandWindows();
60 bool CGUIWindowManager::SendMessage(int message, int senderID, int destID, int param1, int param2)
62 CGUIMessage msg(message, senderID, destID, param1, param2);
63 return SendMessage(msg);
66 bool CGUIWindowManager::SendMessage(CGUIMessage& message)
69 // CLog::Log(LOGDEBUG,"SendMessage: mess=%d send=%d control=%d param1=%d", message.GetMessage(), message.GetSenderId(), message.GetControlId(), message.GetParam1());
70 // Send the message to all none window targets
71 for (int i = 0; i < (int) m_vecMsgTargets.size(); i++)
73 IMsgTargetCallback* pMsgTarget = m_vecMsgTargets[i];
77 if (pMsgTarget->OnMessage( message )) handled = true;
81 // A GUI_MSG_NOTIFY_ALL is send to any active modal dialog
82 // and all windows whether they are active or not
83 if (message.GetMessage()==GUI_MSG_NOTIFY_ALL)
85 CSingleLock lock(g_graphicsContext);
86 for (rDialog it = m_activeDialogs.rbegin(); it != m_activeDialogs.rend(); ++it)
88 CGUIWindow *dialog = *it;
89 dialog->OnMessage(message);
92 for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); ++it)
94 CGUIWindow *pWindow = (*it).second;
95 pWindow->OnMessage(message);
100 // Normal messages are sent to:
101 // 1. All active modeless dialogs
102 // 2. The topmost dialog that accepts the message
103 // 3. The underlying window (only if it is the sender or receiver if a modal dialog is active)
105 bool hasModalDialog(false);
106 bool modalAcceptedMessage(false);
107 // don't use an iterator for this loop, as some messages mean that m_activeDialogs is altered,
108 // which will invalidate any iterator
109 CSingleLock lock(g_graphicsContext);
110 unsigned int topWindow = m_activeDialogs.size();
113 CGUIWindow* dialog = m_activeDialogs[--topWindow];
115 if (!modalAcceptedMessage && dialog->IsModalDialog())
117 hasModalDialog = true;
118 if (!modalAcceptedMessage && dialog->OnMessage( message ))
120 modalAcceptedMessage = handled = true;
123 else if (!dialog->IsModalDialog())
125 if (dialog->OnMessage( message ))
129 if (topWindow > m_activeDialogs.size())
130 topWindow = m_activeDialogs.size();
134 // now send to the underlying window
135 CGUIWindow* window = GetWindow(GetActiveWindow());
140 // only send the message to the underlying window if it's the recipient
141 // or sender (or we have no sender)
142 if (message.GetSenderId() == window->GetID() ||
143 message.GetControlId() == window->GetID() ||
144 message.GetSenderId() == 0 )
146 if (window->OnMessage(message)) handled = true;
151 if (window->OnMessage(message)) handled = true;
157 bool CGUIWindowManager::SendMessage(CGUIMessage& message, int window)
160 // send to no specified windows.
161 return SendMessage(message);
162 CGUIWindow* pWindow = GetWindow(window);
164 return pWindow->OnMessage(message);
169 void CGUIWindowManager::AddUniqueInstance(CGUIWindow *window)
171 CSingleLock lock(g_graphicsContext);
172 // increment our instance (upper word of windowID)
173 // until we get a window we don't have
175 while (GetWindow(window->GetID()))
176 window->SetID(window->GetID() + (++instance << 16));
180 void CGUIWindowManager::Add(CGUIWindow* pWindow)
184 CLog::Log(LOGERROR, "Attempted to add a NULL window pointer to the window manager.");
187 // push back all the windows if there are more than one covered by this class
188 CSingleLock lock(g_graphicsContext);
189 m_idCache.Invalidate();
190 const vector<int>& idRange = pWindow->GetIDRange();
191 for (vector<int>::const_iterator idIt = idRange.begin(); idIt != idRange.end() ; ++idIt)
193 WindowMap::iterator it = m_mapWindows.find(*idIt);
194 if (it != m_mapWindows.end())
196 CLog::Log(LOGERROR, "Error, trying to add a second window with id %u "
197 "to the window manager", *idIt);
200 m_mapWindows.insert(pair<int, CGUIWindow *>(*idIt, pWindow));
204 void CGUIWindowManager::AddCustomWindow(CGUIWindow* pWindow)
206 CSingleLock lock(g_graphicsContext);
208 m_vecCustomWindows.push_back(pWindow);
211 void CGUIWindowManager::AddModeless(CGUIWindow* dialog)
213 CSingleLock lock(g_graphicsContext);
214 // only add the window if it's not already added
215 for (iDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
216 if (*it == dialog) return;
217 m_activeDialogs.push_back(dialog);
220 void CGUIWindowManager::Remove(int id)
222 CSingleLock lock(g_graphicsContext);
223 m_idCache.Invalidate();
224 WindowMap::iterator it = m_mapWindows.find(id);
225 if (it != m_mapWindows.end())
227 for(vector<CGUIWindow*>::iterator it2 = m_activeDialogs.begin(); it2 != m_activeDialogs.end();)
229 if(*it2 == it->second)
230 it2 = m_activeDialogs.erase(it2);
235 m_mapWindows.erase(it);
239 CLog::Log(LOGWARNING, "Attempted to remove window %u "
240 "from the window manager when it didn't exist",
245 // removes and deletes the window. Should only be called
246 // from the class that created the window using new.
247 void CGUIWindowManager::Delete(int id)
249 CSingleLock lock(g_graphicsContext);
250 CGUIWindow *pWindow = GetWindow(id);
254 m_deleteWindows.push_back(pWindow);
258 void CGUIWindowManager::PreviousWindow()
260 // deactivate any window
261 CSingleLock lock(g_graphicsContext);
262 CLog::Log(LOGDEBUG,"CGUIWindowManager::PreviousWindow: Deactivate");
263 int currentWindow = GetActiveWindow();
264 CGUIWindow *pCurrentWindow = GetWindow(currentWindow);
266 return; // no windows or window history yet
268 // check to see whether our current window has a <previouswindow> tag
269 if (pCurrentWindow->GetPreviousWindow() != WINDOW_INVALID)
271 // TODO: we may need to test here for the
272 // whether our history should be changed
274 // don't reactivate the previouswindow if it is ourselves.
275 if (currentWindow != pCurrentWindow->GetPreviousWindow())
276 ActivateWindow(pCurrentWindow->GetPreviousWindow());
279 // get the previous window in our stack
280 if (m_windowHistory.size() < 2)
281 { // no previous window history yet - check if we should just activate home
282 if (GetActiveWindow() != WINDOW_INVALID && GetActiveWindow() != WINDOW_HOME)
284 ClearWindowHistory();
285 ActivateWindow(WINDOW_HOME);
289 m_windowHistory.pop();
290 int previousWindow = GetActiveWindow();
291 m_windowHistory.push(currentWindow);
293 CGUIWindow *pNewWindow = GetWindow(previousWindow);
296 CLog::Log(LOGERROR, "Unable to activate the previous window");
297 ClearWindowHistory();
298 ActivateWindow(WINDOW_HOME);
302 // ok to go to the previous window now
304 // tell our info manager which window we are going to
305 g_infoManager.SetNextWindow(previousWindow);
307 // set our overlay state (enables out animations on window change)
308 HideOverlay(pNewWindow->GetOverlayState());
310 // deinitialize our window
311 CloseWindowSync(pCurrentWindow);
313 g_infoManager.SetNextWindow(WINDOW_INVALID);
314 g_infoManager.SetPreviousWindow(currentWindow);
316 // remove the current window off our window stack
317 m_windowHistory.pop();
319 // ok, initialize the new window
320 CLog::Log(LOGDEBUG,"CGUIWindowManager::PreviousWindow: Activate new");
321 CGUIMessage msg2(GUI_MSG_WINDOW_INIT, 0, 0, WINDOW_INVALID, GetActiveWindow());
322 pNewWindow->OnMessage(msg2);
324 g_infoManager.SetPreviousWindow(WINDOW_INVALID);
328 void CGUIWindowManager::ChangeActiveWindow(int newWindow, const CStdString& strPath)
330 vector<CStdString> params;
331 if (!strPath.empty())
332 params.push_back(strPath);
333 ActivateWindow(newWindow, params, true);
336 void CGUIWindowManager::ActivateWindow(int iWindowID, const CStdString& strPath)
338 vector<CStdString> params;
339 if (!strPath.empty())
340 params.push_back(strPath);
341 ActivateWindow(iWindowID, params, false);
344 void CGUIWindowManager::ActivateWindow(int iWindowID, const vector<CStdString>& params, bool swappingWindows)
346 if (!g_application.IsCurrentThread())
348 // make sure graphics lock is not held
349 CSingleExit leaveIt(g_graphicsContext);
350 CApplicationMessenger::Get().ActivateWindow(iWindowID, params, swappingWindows);
354 CSingleLock lock(g_graphicsContext);
355 ActivateWindow_Internal(iWindowID, params, swappingWindows);
359 void CGUIWindowManager::ActivateWindow_Internal(int iWindowID, const vector<CStdString>& params, bool swappingWindows)
361 // translate virtual windows
362 // virtual music window which returns the last open music window (aka the music start window)
363 if (iWindowID == WINDOW_MUSIC)
365 iWindowID = CSettings::Get().GetInt("mymusic.startwindow");
366 // ensure the music virtual window only returns music files and music library windows
367 if (iWindowID != WINDOW_MUSIC_NAV)
368 iWindowID = WINDOW_MUSIC_FILES;
370 // virtual video window which returns the last open video window (aka the video start window)
371 if (iWindowID == WINDOW_VIDEOS || iWindowID == WINDOW_VIDEO_FILES)
372 { // backward compatibility for pre-Eden
373 iWindowID = WINDOW_VIDEO_NAV;
375 if (iWindowID == WINDOW_SCRIPTS)
376 { // backward compatibility for pre-Dharma
377 iWindowID = WINDOW_PROGRAMS;
379 if (iWindowID == WINDOW_START)
380 { // virtual start window
381 iWindowID = g_SkinInfo->GetStartWindow();
385 CLog::Log(LOGDEBUG, "Activating window ID: %i", iWindowID);
387 if (!g_passwordManager.CheckMenuLock(iWindowID))
389 CLog::Log(LOGERROR, "MasterCode is Wrong: Window with id %d will not be loaded! Enter a correct MasterCode!", iWindowID);
390 if (GetActiveWindow() == WINDOW_INVALID && iWindowID != WINDOW_HOME)
391 ActivateWindow(WINDOW_HOME);
395 // first check existence of the window we wish to activate.
396 CGUIWindow *pNewWindow = GetWindow(iWindowID);
398 { // nothing to see here - move along
399 CLog::Log(LOGERROR, "Unable to locate window with id %d. Check skin files", iWindowID - WINDOW_HOME);
402 else if (pNewWindow->IsDialog())
403 { // if we have a dialog, we do a DoModal() rather than activate the window
404 if (!pNewWindow->IsDialogRunning())
406 CSingleExit exitit(g_graphicsContext);
407 ((CGUIDialog *)pNewWindow)->DoModal(iWindowID, params.size() ? params[0] : "");
412 g_infoManager.SetNextWindow(iWindowID);
414 // set our overlay state
415 HideOverlay(pNewWindow->GetOverlayState());
417 // deactivate any window
418 int currentWindow = GetActiveWindow();
419 CGUIWindow *pWindow = GetWindow(currentWindow);
421 CloseWindowSync(pWindow, iWindowID);
422 g_infoManager.SetNextWindow(WINDOW_INVALID);
424 // Add window to the history list (we must do this before we activate it,
425 // as all messages done in WINDOW_INIT will want to be sent to the new
426 // topmost window). If we are swapping windows, we pop the old window
427 // off the history stack
428 if (swappingWindows && !m_windowHistory.empty())
429 m_windowHistory.pop();
430 AddToWindowHistory(iWindowID);
432 g_infoManager.SetPreviousWindow(currentWindow);
433 // Send the init message
434 CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0, 0, currentWindow, iWindowID);
435 msg.SetStringParams(params);
436 pNewWindow->OnMessage(msg);
437 // g_infoManager.SetPreviousWindow(WINDOW_INVALID);
440 void CGUIWindowManager::CloseDialogs(bool forceClose) const
442 CSingleLock lock(g_graphicsContext);
443 while (m_activeDialogs.size() > 0)
445 CGUIWindow* win = m_activeDialogs[0];
446 win->Close(forceClose);
450 bool CGUIWindowManager::OnAction(const CAction &action) const
452 CSingleLock lock(g_graphicsContext);
453 unsigned int topMost = m_activeDialogs.size();
456 CGUIWindow *dialog = m_activeDialogs[--topMost];
458 if (dialog->IsModalDialog())
459 { // we have the topmost modal dialog
460 if (!dialog->IsAnimating(ANIM_TYPE_WINDOW_CLOSE))
462 bool fallThrough = (dialog->GetID() == WINDOW_DIALOG_FULLSCREEN_INFO);
463 if (dialog->OnAction(action))
465 // dialog didn't want the action - we'd normally return false
466 // but for some dialogs we want to drop the actions through
471 return true; // do nothing with the action until the anim is finished
473 // music or video overlay are handled as a special case, as they're modeless, but we allow
474 // clicking on them with the mouse.
475 if (action.IsMouse() && (dialog->GetID() == WINDOW_DIALOG_VIDEO_OVERLAY ||
476 dialog->GetID() == WINDOW_DIALOG_MUSIC_OVERLAY))
478 if (dialog->OnAction(action))
482 if (topMost > m_activeDialogs.size())
483 topMost = m_activeDialogs.size();
486 CGUIWindow* window = GetWindow(GetActiveWindow());
488 return window->OnAction(action);
492 bool RenderOrderSortFunction(CGUIWindow *first, CGUIWindow *second)
494 return first->GetRenderOrder() < second->GetRenderOrder();
497 void CGUIWindowManager::Process(unsigned int currentTime)
499 assert(g_application.IsCurrentThread());
500 CSingleLock lock(g_graphicsContext);
502 CDirtyRegionList dirtyregions;
504 CGUIWindow* pWindow = GetWindow(GetActiveWindow());
506 pWindow->DoProcess(currentTime, dirtyregions);
508 // process all dialogs - visibility may change etc.
509 for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); ++it)
511 CGUIWindow *pWindow = (*it).second;
512 if (pWindow && pWindow->IsDialog())
513 pWindow->DoProcess(currentTime, dirtyregions);
516 for (CDirtyRegionList::iterator itr = dirtyregions.begin(); itr != dirtyregions.end(); ++itr)
517 m_tracker.MarkDirtyRegion(*itr);
520 void CGUIWindowManager::MarkDirty()
522 m_tracker.MarkDirtyRegion(CRect(0, 0, (float)g_graphicsContext.GetWidth(), (float)g_graphicsContext.GetHeight()));
525 void CGUIWindowManager::MarkDirty(const CRect& rect)
527 m_tracker.MarkDirtyRegion(rect);
530 void CGUIWindowManager::RenderPass() const
532 CGUIWindow* pWindow = GetWindow(GetActiveWindow());
535 pWindow->ClearBackground();
539 // we render the dialogs based on their render order.
540 vector<CGUIWindow *> renderList = m_activeDialogs;
541 stable_sort(renderList.begin(), renderList.end(), RenderOrderSortFunction);
543 for (iDialog it = renderList.begin(); it != renderList.end(); ++it)
545 if ((*it)->IsDialogRunning())
550 bool CGUIWindowManager::Render()
552 assert(g_application.IsCurrentThread());
553 CSingleLock lock(g_graphicsContext);
555 CDirtyRegionList dirtyRegions = m_tracker.GetDirtyRegions();
557 bool hasRendered = false;
558 // If we visualize the regions we will always render the entire viewport
559 if (g_advancedSettings.m_guiVisualizeDirtyRegions || g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_FILL_VIEWPORT_ALWAYS)
564 else if (g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_FILL_VIEWPORT_ON_CHANGE)
566 if (dirtyRegions.size() > 0)
574 for (CDirtyRegionList::const_iterator i = dirtyRegions.begin(); i != dirtyRegions.end(); ++i)
579 g_graphicsContext.SetScissors(*i);
583 g_graphicsContext.ResetScissors();
586 if (g_advancedSettings.m_guiVisualizeDirtyRegions)
588 g_graphicsContext.SetRenderingResolution(g_graphicsContext.GetResInfo(), false);
589 const CDirtyRegionList &markedRegions = m_tracker.GetMarkedRegions();
590 for (CDirtyRegionList::const_iterator i = markedRegions.begin(); i != markedRegions.end(); ++i)
591 CGUITexture::DrawQuad(*i, 0x0fff0000);
592 for (CDirtyRegionList::const_iterator i = dirtyRegions.begin(); i != dirtyRegions.end(); ++i)
593 CGUITexture::DrawQuad(*i, 0x4c00ff00);
599 void CGUIWindowManager::AfterRender()
601 m_tracker.CleanMarkedRegions();
603 CGUIWindow* pWindow = GetWindow(GetActiveWindow());
605 pWindow->AfterRender();
607 // make copy of vector as we may remove items from it as we go
608 vector<CGUIWindow *> activeDialogs = m_activeDialogs;
609 for (iDialog it = activeDialogs.begin(); it != activeDialogs.end(); ++it)
611 if ((*it)->IsDialogRunning())
612 (*it)->AfterRender();
616 void CGUIWindowManager::FrameMove()
618 assert(g_application.IsCurrentThread());
619 CSingleLock lock(g_graphicsContext);
623 // delete any windows queued for deletion
624 for(iDialog it = m_deleteWindows.begin(); it != m_deleteWindows.end(); ++it)
626 // Free any window resources
627 (*it)->FreeResources(true);
630 m_deleteWindows.clear();
633 CGUIWindow* pWindow = GetWindow(GetActiveWindow());
635 pWindow->FrameMove();
636 // update any dialogs - we take a copy of the vector as some dialogs may close themselves
638 vector<CGUIWindow *> dialogs = m_activeDialogs;
639 for (iDialog it = dialogs.begin(); it != dialogs.end(); ++it)
642 g_infoManager.m_AVInfoValid = false;
645 CGUIWindow* CGUIWindowManager::GetWindow(int id) const
648 if (id == 0 || id == WINDOW_INVALID)
650 window = m_idCache.Get(id);
654 CSingleLock lock(g_graphicsContext);
655 WindowMap::const_iterator it = m_mapWindows.find(id);
656 if (it != m_mapWindows.end())
657 window = (*it).second;
660 m_idCache.Set(id, window);
664 void CGUIWindowManager::ProcessRenderLoop(bool renderOnly /*= false*/)
666 if (g_application.IsCurrentThread() && m_pCallback)
670 m_pCallback->Process();
671 m_pCallback->FrameMove(!renderOnly);
672 m_pCallback->Render();
677 void CGUIWindowManager::SetCallback(IWindowManagerCallback& callback)
679 m_pCallback = &callback;
682 void CGUIWindowManager::DeInitialize()
684 CSingleLock lock(g_graphicsContext);
685 for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); ++it)
687 CGUIWindow* pWindow = (*it).second;
688 if (IsWindowActive(it->first))
690 pWindow->DisableAnimations();
691 pWindow->Close(true);
693 pWindow->ResetControlStates();
694 pWindow->FreeResources(true);
696 UnloadNotOnDemandWindows();
698 m_vecMsgTargets.erase( m_vecMsgTargets.begin(), m_vecMsgTargets.end() );
700 // destroy our custom windows...
701 for (int i = 0; i < (int)m_vecCustomWindows.size(); i++)
703 CGUIWindow *pWindow = m_vecCustomWindows[i];
704 Remove(pWindow->GetID());
708 // clear our vectors of windows
709 m_vecCustomWindows.clear();
710 m_activeDialogs.clear();
712 m_initialized = false;
715 /// \brief Route to a window
716 /// \param pWindow Window to route to
717 void CGUIWindowManager::RouteToWindow(CGUIWindow* dialog)
719 CSingleLock lock(g_graphicsContext);
720 // Just to be sure: Unroute this window,
721 // #we may have routed to it before
722 RemoveDialog(dialog->GetID());
724 m_activeDialogs.push_back(dialog);
727 /// \brief Unroute window
728 /// \param id ID of the window routed
729 void CGUIWindowManager::RemoveDialog(int id)
731 CSingleLock lock(g_graphicsContext);
732 for (iDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
734 if ((*it)->GetID() == id)
736 m_activeDialogs.erase(it);
742 bool CGUIWindowManager::HasModalDialog() const
744 CSingleLock lock(g_graphicsContext);
745 for (ciDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
747 CGUIWindow *window = *it;
748 if (window->IsModalDialog())
749 { // have a modal window
750 if (!window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE))
757 bool CGUIWindowManager::HasDialogOnScreen() const
759 return (m_activeDialogs.size() > 0);
762 /// \brief Get the ID of the top most routed window
763 /// \return id ID of the window or WINDOW_INVALID if no routed window available
764 int CGUIWindowManager::GetTopMostModalDialogID(bool ignoreClosing /*= false*/) const
766 CSingleLock lock(g_graphicsContext);
767 for (crDialog it = m_activeDialogs.rbegin(); it != m_activeDialogs.rend(); ++it)
769 CGUIWindow *dialog = *it;
770 if (dialog->IsModalDialog() && (!ignoreClosing || !dialog->IsAnimating(ANIM_TYPE_WINDOW_CLOSE)))
771 { // have a modal window
772 return dialog->GetID();
775 return WINDOW_INVALID;
778 void CGUIWindowManager::SendThreadMessage(CGUIMessage& message, int window /*= 0*/)
780 CSingleLock lock(m_critSection);
782 CGUIMessage* msg = new CGUIMessage(message);
783 m_vecThreadMessages.push_back( pair<CGUIMessage*,int>(msg,window) );
786 void CGUIWindowManager::DispatchThreadMessages()
788 // This method only be called in the xbmc main thread.
790 // XXX: for more info of this method
791 // check the pr here: https://github.com/xbmc/xbmc/pull/2253
793 // As a thread message queue service, it should follow these rules:
794 // 1. [Must] Thread safe, message can be pushed into queue in arbitrary thread context.
795 // 2. Messages [must] be processed in dispatch message thread context with the same
796 // order as they be pushed into the queue.
797 // 3. Dispatch function [must] support call itself during message process procedure,
798 // and do not break other rules listed here. to make it clear: in the
799 // SendMessage(), it could start another xbmc main thread loop, calling
800 // DispatchThreadMessages() in it's internal loop, this must be supported.
801 // 4. During DispatchThreadMessages() processing, any new pushed message [should] not
802 // be processed by the current loop in DispatchThreadMessages(), prevent dead loop.
803 // 5. If possible, queued messages can be removed by certain filter condition
804 // and not break above.
806 CSingleLock lock(m_critSection);
808 for(int msgCount = m_vecThreadMessages.size(); !m_vecThreadMessages.empty() && msgCount > 0; --msgCount)
810 // pop up one message per time to make messages be processed by order.
811 // this will ensure rule No.2 & No.3
812 CGUIMessage *pMsg = m_vecThreadMessages.front().first;
813 int window = m_vecThreadMessages.front().second;
814 m_vecThreadMessages.pop_front();
818 // XXX: during SendMessage(), there could be a deeper 'xbmc main loop' inited by e.g. doModal
819 // which may loop there and callback to DispatchThreadMessages() multiple times.
821 SendMessage( *pMsg, window );
823 SendMessage( *pMsg );
830 int CGUIWindowManager::RemoveThreadMessageByMessageIds(int *pMessageIDList)
832 CSingleLock lock(m_critSection);
833 int removedMsgCount = 0;
834 for (std::list < std::pair<CGUIMessage*,int> >::iterator it = m_vecThreadMessages.begin();
835 it != m_vecThreadMessages.end();)
837 CGUIMessage *pMsg = it->first;
839 for(pMsgID = pMessageIDList; *pMsgID != 0; ++pMsgID)
840 if (pMsg->GetMessage() == *pMsgID)
844 it = m_vecThreadMessages.erase(it);
853 return removedMsgCount;
856 void CGUIWindowManager::AddMsgTarget( IMsgTargetCallback* pMsgTarget )
858 m_vecMsgTargets.push_back( pMsgTarget );
861 int CGUIWindowManager::GetActiveWindow() const
863 if (!m_windowHistory.empty())
864 return m_windowHistory.top();
865 return WINDOW_INVALID;
868 // same as GetActiveWindow() except it first grabs dialogs
869 int CGUIWindowManager::GetFocusedWindow() const
871 int dialog = GetTopMostModalDialogID(true);
872 if (dialog != WINDOW_INVALID)
875 return GetActiveWindow();
878 bool CGUIWindowManager::IsWindowActive(int id, bool ignoreClosing /* = true */) const
880 // mask out multiple instances of the same window
881 id &= WINDOW_ID_MASK;
882 if ((GetActiveWindow() & WINDOW_ID_MASK) == id) return true;
883 // run through the dialogs
884 CSingleLock lock(g_graphicsContext);
885 for (ciDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
887 CGUIWindow *window = *it;
888 if ((window->GetID() & WINDOW_ID_MASK) == id && (!ignoreClosing || !window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE)))
891 return false; // window isn't active
894 bool CGUIWindowManager::IsWindowActive(const CStdString &xmlFile, bool ignoreClosing /* = true */) const
896 CSingleLock lock(g_graphicsContext);
897 CGUIWindow *window = GetWindow(GetActiveWindow());
898 if (window && URIUtils::GetFileName(window->GetProperty("xmlfile").asString()).Equals(xmlFile)) return true;
899 // run through the dialogs
900 for (ciDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
902 CGUIWindow *window = *it;
903 if (URIUtils::GetFileName(window->GetProperty("xmlfile").asString()).Equals(xmlFile) && (!ignoreClosing || !window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE)))
906 return false; // window isn't active
909 bool CGUIWindowManager::IsWindowVisible(int id) const
911 return IsWindowActive(id, false);
914 bool CGUIWindowManager::IsWindowVisible(const CStdString &xmlFile) const
916 return IsWindowActive(xmlFile, false);
919 void CGUIWindowManager::LoadNotOnDemandWindows()
921 CSingleLock lock(g_graphicsContext);
922 for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); ++it)
924 CGUIWindow *pWindow = (*it).second;
925 if (pWindow->GetLoadType() == CGUIWindow::LOAD_ON_GUI_INIT)
927 pWindow->FreeResources(true);
928 pWindow->Initialize();
933 void CGUIWindowManager::UnloadNotOnDemandWindows()
935 CSingleLock lock(g_graphicsContext);
936 for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); ++it)
938 CGUIWindow *pWindow = (*it).second;
939 if (pWindow->GetLoadType() == CGUIWindow::LOAD_ON_GUI_INIT ||
940 pWindow->GetLoadType() == CGUIWindow::KEEP_IN_MEMORY)
942 pWindow->FreeResources(true);
947 bool CGUIWindowManager::IsOverlayAllowed() const
949 if (GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO ||
950 GetActiveWindow() == WINDOW_SCREENSAVER)
952 return m_bShowOverlay;
955 void CGUIWindowManager::ShowOverlay(CGUIWindow::OVERLAY_STATE state)
957 if (state != CGUIWindow::OVERLAY_STATE_PARENT_WINDOW)
958 m_bShowOverlay = state == CGUIWindow::OVERLAY_STATE_SHOWN;
961 void CGUIWindowManager::HideOverlay(CGUIWindow::OVERLAY_STATE state)
963 if (state == CGUIWindow::OVERLAY_STATE_HIDDEN)
964 m_bShowOverlay = false;
967 void CGUIWindowManager::AddToWindowHistory(int newWindowID)
969 // Check the window stack to see if this window is in our history,
970 // and if so, pop all the other windows off the stack so that we
971 // always have a predictable "Back" behaviour for each window
972 stack<int> historySave = m_windowHistory;
973 while (!historySave.empty())
975 if (historySave.top() == newWindowID)
979 if (!historySave.empty())
980 { // found window in history
981 m_windowHistory = historySave;
984 { // didn't find window in history - add it to the stack
985 m_windowHistory.push(newWindowID);
989 void CGUIWindowManager::GetActiveModelessWindows(vector<int> &ids)
991 // run through our modeless windows, and construct a vector of them
992 // useful for saving and restoring the modeless windows on skin change etc.
993 CSingleLock lock(g_graphicsContext);
994 for (iDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
996 if (!(*it)->IsModalDialog())
997 ids.push_back((*it)->GetID());
1001 CGUIWindow *CGUIWindowManager::GetTopMostDialog() const
1003 CSingleLock lock(g_graphicsContext);
1004 // find the window with the lowest render order
1005 vector<CGUIWindow *> renderList = m_activeDialogs;
1006 stable_sort(renderList.begin(), renderList.end(), RenderOrderSortFunction);
1008 if (!renderList.size())
1011 // return the last window in the list
1012 return *renderList.rbegin();
1015 bool CGUIWindowManager::IsWindowTopMost(int id) const
1017 CGUIWindow *topMost = GetTopMostDialog();
1018 if (topMost && (topMost->GetID() & WINDOW_ID_MASK) == id)
1023 bool CGUIWindowManager::IsWindowTopMost(const CStdString &xmlFile) const
1025 CGUIWindow *topMost = GetTopMostDialog();
1026 if (topMost && URIUtils::GetFileName(topMost->GetProperty("xmlfile").asString()).Equals(xmlFile))
1031 void CGUIWindowManager::ClearWindowHistory()
1033 while (!m_windowHistory.empty())
1034 m_windowHistory.pop();
1037 void CGUIWindowManager::CloseWindowSync(CGUIWindow *window, int nextWindowID /*= 0*/)
1039 window->Close(false, nextWindowID);
1040 while (window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE))
1041 ProcessRenderLoop(true);
1045 void CGUIWindowManager::DumpTextureUse()
1047 CGUIWindow* pWindow = GetWindow(GetActiveWindow());
1049 pWindow->DumpTextureUse();
1051 CSingleLock lock(g_graphicsContext);
1052 for (iDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
1054 if ((*it)->IsDialogRunning())
1055 (*it)->DumpTextureUse();