354aeb5fc200171f53dccae66450ec462df4ea3f
[vuplus_xbmc] / guilib / GUIWindowManager.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "GUIWindowManager.h"
23 #include "GUIAudioManager.h"
24 #include "GUIDialog.h"
25 #include "Application.h"
26 #include "GUIPassword.h"
27 #include "utils/GUIInfoManager.h"
28 #include "utils/SingleLock.h"
29 #include "Util.h"
30 #include "GUISettings.h"
31 #include "Settings.h"
32 #include "addons/Skin.h"
33
34 using namespace std;
35
36 CGUIWindowManager g_windowManager;
37
38 CGUIWindowManager::CGUIWindowManager(void)
39 {
40   m_pCallback = NULL;
41   m_bShowOverlay = true;
42   m_iNested = 0;
43 }
44
45 CGUIWindowManager::~CGUIWindowManager(void)
46 {
47 }
48
49 void CGUIWindowManager::Initialize()
50 {
51   LoadNotOnDemandWindows();
52 }
53
54 bool CGUIWindowManager::SendMessage(int message, int senderID, int destID, int param1, int param2)
55 {
56   CGUIMessage msg(message, senderID, destID, param1, param2);
57   return SendMessage(msg);
58 }
59
60 bool CGUIWindowManager::SendMessage(CGUIMessage& message)
61 {
62   bool handled = false;
63 //  CLog::Log(LOGDEBUG,"SendMessage: mess=%d send=%d control=%d param1=%d", message.GetMessage(), message.GetSenderId(), message.GetControlId(), message.GetParam1());
64   // Send the message to all none window targets
65   for (int i = 0; i < (int) m_vecMsgTargets.size(); i++)
66   {
67     IMsgTargetCallback* pMsgTarget = m_vecMsgTargets[i];
68
69     if (pMsgTarget)
70     {
71       if (pMsgTarget->OnMessage( message )) handled = true;
72     }
73   }
74
75   //  A GUI_MSG_NOTIFY_ALL is send to any active modal dialog
76   //  and all windows whether they are active or not
77   if (message.GetMessage()==GUI_MSG_NOTIFY_ALL)
78   {
79     CSingleLock lock(g_graphicsContext);
80     for (rDialog it = m_activeDialogs.rbegin(); it != m_activeDialogs.rend(); ++it)
81     {
82       CGUIWindow *dialog = *it;
83       dialog->OnMessage(message);
84     }
85
86     for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); it++)
87     {
88       CGUIWindow *pWindow = (*it).second;
89       pWindow->OnMessage(message);
90     }
91     return true;
92   }
93
94   // Normal messages are sent to:
95   // 1. All active modeless dialogs
96   // 2. The topmost dialog that accepts the message
97   // 3. The underlying window (only if it is the sender or receiver if a modal dialog is active)
98
99   bool hasModalDialog(false);
100   bool modalAcceptedMessage(false);
101   // don't use an iterator for this loop, as some messages mean that m_activeDialogs is altered,
102   // which will invalidate any iterator
103   CSingleLock lock(g_graphicsContext);
104   unsigned int topWindow = m_activeDialogs.size();
105   while (topWindow)
106   {
107     CGUIWindow* dialog = m_activeDialogs[--topWindow];
108     lock.Leave();
109     if (!modalAcceptedMessage && dialog->IsModalDialog())
110     { // modal window
111       hasModalDialog = true;
112       if (!modalAcceptedMessage && dialog->OnMessage( message ))
113       {
114         modalAcceptedMessage = handled = true;
115       }
116     }
117     else if (!dialog->IsModalDialog())
118     { // modeless
119       if (dialog->OnMessage( message ))
120         handled = true;
121     }
122     lock.Enter();
123     if (topWindow > m_activeDialogs.size())
124       topWindow = m_activeDialogs.size();
125   }
126   lock.Leave();
127
128   // now send to the underlying window
129   CGUIWindow* window = GetWindow(GetActiveWindow());
130   if (window)
131   {
132     if (hasModalDialog)
133     {
134       // only send the message to the underlying window if it's the recipient
135       // or sender (or we have no sender)
136       if (message.GetSenderId() == window->GetID() ||
137           message.GetControlId() == window->GetID() ||
138           message.GetSenderId() == 0 )
139       {
140         if (window->OnMessage(message)) handled = true;
141       }
142     }
143     else
144     {
145       if (window->OnMessage(message)) handled = true;
146     }
147   }
148   return handled;
149 }
150
151 bool CGUIWindowManager::SendMessage(CGUIMessage& message, int window)
152 {
153   CGUIWindow* pWindow = GetWindow(window);
154   if(pWindow)
155     return pWindow->OnMessage(message);
156   else
157     return false;
158 }
159
160 void CGUIWindowManager::AddUniqueInstance(CGUIWindow *window)
161 {
162   CSingleLock lock(g_graphicsContext);
163   // increment our instance (upper word of windowID)
164   // until we get a window we don't have
165   int instance = 0;
166   while (GetWindow(window->GetID()))
167     window->SetID(window->GetID() + (++instance << 16));
168   Add(window);
169 }
170
171 void CGUIWindowManager::Add(CGUIWindow* pWindow)
172 {
173   if (!pWindow)
174   {
175     CLog::Log(LOGERROR, "Attempted to add a NULL window pointer to the window manager.");
176     return;
177   }
178   // push back all the windows if there are more than one covered by this class
179   CSingleLock lock(g_graphicsContext);
180   for (int i = 0; i < pWindow->GetIDRange(); i++)
181   {
182     WindowMap::iterator it = m_mapWindows.find(pWindow->GetID() + i);
183     if (it != m_mapWindows.end())
184     {
185       CLog::Log(LOGERROR, "Error, trying to add a second window with id %u "
186                           "to the window manager",
187                 pWindow->GetID());
188       return;
189     }
190     m_mapWindows.insert(pair<int, CGUIWindow *>(pWindow->GetID() + i, pWindow));
191   }
192 }
193
194 void CGUIWindowManager::AddCustomWindow(CGUIWindow* pWindow)
195 {
196   CSingleLock lock(g_graphicsContext);
197   Add(pWindow);
198   m_vecCustomWindows.push_back(pWindow);
199 }
200
201 void CGUIWindowManager::AddModeless(CGUIWindow* dialog)
202 {
203   CSingleLock lock(g_graphicsContext);
204   // only add the window if it's not already added
205   for (iDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
206     if (*it == dialog) return;
207   m_activeDialogs.push_back(dialog);
208 }
209
210 void CGUIWindowManager::Remove(int id)
211 {
212   CSingleLock lock(g_graphicsContext);
213   WindowMap::iterator it = m_mapWindows.find(id);
214   if (it != m_mapWindows.end())
215   {
216     for(vector<CGUIWindow*>::iterator it2 = m_activeDialogs.begin(); it2 != m_activeDialogs.end();)
217     {
218       if(*it2 == it->second)
219         it2 = m_activeDialogs.erase(it2);
220       else
221         it2++;
222     }
223
224     m_mapWindows.erase(it);
225   }
226   else
227   {
228     CLog::Log(LOGWARNING, "Attempted to remove window %u "
229                           "from the window manager when it didn't exist",
230               id);
231   }
232 }
233
234 // removes and deletes the window.  Should only be called
235 // from the class that created the window using new.
236 void CGUIWindowManager::Delete(int id)
237 {
238   CSingleLock lock(g_graphicsContext);
239   CGUIWindow *pWindow = GetWindow(id);
240   if (pWindow)
241   {
242     Remove(id);
243     m_deleteWindows.push_back(pWindow);
244   }
245 }
246
247 void CGUIWindowManager::PreviousWindow()
248 {
249   // deactivate any window
250   CSingleLock lock(g_graphicsContext);
251   CLog::Log(LOGDEBUG,"CGUIWindowManager::PreviousWindow: Deactivate");
252   int currentWindow = GetActiveWindow();
253   CGUIWindow *pCurrentWindow = GetWindow(currentWindow);
254   if (!pCurrentWindow)
255     return;     // no windows or window history yet
256
257   // check to see whether our current window has a <previouswindow> tag
258   if (pCurrentWindow->GetPreviousWindow() != WINDOW_INVALID)
259   {
260     // TODO: we may need to test here for the
261     //       whether our history should be changed
262
263     // don't reactivate the previouswindow if it is ourselves.
264     if (currentWindow != pCurrentWindow->GetPreviousWindow())
265       ActivateWindow(pCurrentWindow->GetPreviousWindow());
266     return;
267   }
268   // get the previous window in our stack
269   if (m_windowHistory.size() < 2)
270   { // no previous window history yet - check if we should just activate home
271     if (GetActiveWindow() != WINDOW_INVALID && GetActiveWindow() != WINDOW_HOME)
272     {
273       ClearWindowHistory();
274       ActivateWindow(WINDOW_HOME);
275     }
276     return;
277   }
278   m_windowHistory.pop();
279   int previousWindow = GetActiveWindow();
280   m_windowHistory.push(currentWindow);
281
282   CGUIWindow *pNewWindow = GetWindow(previousWindow);
283   if (!pNewWindow)
284   {
285     CLog::Log(LOGERROR, "Unable to activate the previous window");
286     ClearWindowHistory();
287     ActivateWindow(WINDOW_HOME);
288     return;
289   }
290
291   // ok to go to the previous window now
292
293   // tell our info manager which window we are going to
294   g_infoManager.SetNextWindow(previousWindow);
295
296   // set our overlay state (enables out animations on window change)
297   HideOverlay(pNewWindow->GetOverlayState());
298
299   // deinitialize our window
300   g_audioManager.PlayWindowSound(pCurrentWindow->GetID(), SOUND_DEINIT);
301   CGUIMessage msg(GUI_MSG_WINDOW_DEINIT, 0, 0);
302   pCurrentWindow->OnMessage(msg);
303
304   g_infoManager.SetNextWindow(WINDOW_INVALID);
305   g_infoManager.SetPreviousWindow(currentWindow);
306
307   // remove the current window off our window stack
308   m_windowHistory.pop();
309
310   // ok, initialize the new window
311   CLog::Log(LOGDEBUG,"CGUIWindowManager::PreviousWindow: Activate new");
312   g_audioManager.PlayWindowSound(pNewWindow->GetID(), SOUND_INIT);
313   CGUIMessage msg2(GUI_MSG_WINDOW_INIT, 0, 0, WINDOW_INVALID, GetActiveWindow());
314   pNewWindow->OnMessage(msg2);
315
316   g_infoManager.SetPreviousWindow(WINDOW_INVALID);
317   return;
318 }
319
320 void CGUIWindowManager::ChangeActiveWindow(int newWindow, const CStdString& strPath)
321 {
322   vector<CStdString> params;
323   if (!strPath.IsEmpty())
324     params.push_back(strPath);
325   ActivateWindow(newWindow, params, true);
326 }
327
328 void CGUIWindowManager::ActivateWindow(int iWindowID, const CStdString& strPath)
329 {
330   vector<CStdString> params;
331   if (!strPath.IsEmpty())
332     params.push_back(strPath);
333   ActivateWindow(iWindowID, params, false);
334 }
335
336 void CGUIWindowManager::ActivateWindow(int iWindowID, const vector<CStdString>& params, bool swappingWindows)
337 {
338   if (!g_application.IsCurrentThread())
339   {
340     // make sure graphics lock is not held
341     int nCount = ExitCriticalSection(g_graphicsContext);
342     g_application.getApplicationMessenger().ActivateWindow(iWindowID, params, swappingWindows);
343     RestoreCriticalSection(g_graphicsContext, nCount);
344   }
345   else
346     ActivateWindow_Internal(iWindowID, params, swappingWindows);
347 }
348
349 void CGUIWindowManager::ActivateWindow_Internal(int iWindowID, const vector<CStdString>& params, bool swappingWindows)
350 {
351   bool passParams = true;
352   // translate virtual windows
353   // virtual music window which returns the last open music window (aka the music start window)
354   if (iWindowID == WINDOW_MUSIC)
355   {
356     iWindowID = g_settings.m_iMyMusicStartWindow;
357     // ensure the music virtual window only returns music files and music library windows
358     if (iWindowID != WINDOW_MUSIC_NAV)
359       iWindowID = WINDOW_MUSIC_FILES;
360     // destination path cannot be used with virtual window
361     passParams = false;
362   }
363   // virtual video window which returns the last open video window (aka the video start window)
364   if (iWindowID == WINDOW_VIDEOS)
365   {
366     iWindowID = g_settings.m_iVideoStartWindow;
367     // ensure the virtual video window only returns video windows
368     if (iWindowID != WINDOW_VIDEO_NAV)
369       iWindowID = WINDOW_VIDEO_FILES;
370     // destination path cannot be used with virtual window
371     passParams = false;
372   }
373   if (iWindowID == WINDOW_SCRIPTS)
374   { // backward compatibility for pre-Dharma
375     iWindowID = WINDOW_PROGRAMS;
376   }
377   if (iWindowID == WINDOW_START)
378   { // virtual start window
379     iWindowID = g_SkinInfo->GetStartWindow();
380   }
381
382   // debug
383   CLog::Log(LOGDEBUG, "Activating window ID: %i", iWindowID);
384
385   if (!g_passwordManager.CheckMenuLock(iWindowID))
386   {
387     CLog::Log(LOGERROR, "MasterCode is Wrong: Window with id %d will not be loaded! Enter a correct MasterCode!", iWindowID);
388     if (GetActiveWindow() == WINDOW_INVALID && iWindowID != WINDOW_HOME)
389       ActivateWindow(WINDOW_HOME);
390     return;
391   }
392
393   // first check existence of the window we wish to activate.
394   CGUIWindow *pNewWindow = GetWindow(iWindowID);
395   if (!pNewWindow)
396   { // nothing to see here - move along
397     CLog::Log(LOGERROR, "Unable to locate window with id %d.  Check skin files", iWindowID - WINDOW_HOME);
398     return ;
399   }
400   else if (pNewWindow->IsDialog())
401   { // if we have a dialog, we do a DoModal() rather than activate the window
402     if (!pNewWindow->IsDialogRunning())
403       ((CGUIDialog *)pNewWindow)->DoModal(iWindowID, (passParams && params.size()) ? params[0] : "");
404     return;
405   }
406
407   g_infoManager.SetNextWindow(iWindowID);
408
409   // set our overlay state
410   HideOverlay(pNewWindow->GetOverlayState());
411
412   // deactivate any window
413   int currentWindow = GetActiveWindow();
414   CGUIWindow *pWindow = GetWindow(currentWindow);
415   if (pWindow)
416   {
417     //  Play the window specific deinit sound
418     g_audioManager.PlayWindowSound(pWindow->GetID(), SOUND_DEINIT);
419     CGUIMessage msg(GUI_MSG_WINDOW_DEINIT, 0, 0, iWindowID);
420     pWindow->OnMessage(msg);
421   }
422   g_infoManager.SetNextWindow(WINDOW_INVALID);
423
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.size())
429     m_windowHistory.pop();
430   AddToWindowHistory(iWindowID);
431
432   g_infoManager.SetPreviousWindow(currentWindow);
433   g_audioManager.PlayWindowSound(pNewWindow->GetID(), SOUND_INIT);
434   // Send the init message
435   CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0, 0, currentWindow, iWindowID);
436   if (passParams)
437     msg.SetStringParams(params);
438   pNewWindow->OnMessage(msg);
439 //  g_infoManager.SetPreviousWindow(WINDOW_INVALID);
440 }
441
442 void CGUIWindowManager::CloseDialogs(bool forceClose)
443 {
444   CSingleLock lock(g_graphicsContext);
445   while (m_activeDialogs.size() > 0)
446   {
447     CGUIWindow* win = m_activeDialogs[0];
448     win->Close(forceClose);
449   }
450 }
451
452 bool CGUIWindowManager::OnAction(const CAction &action)
453 {
454   CSingleLock lock(g_graphicsContext);
455   unsigned int topMost = m_activeDialogs.size();
456   while (topMost)
457   {
458     CGUIWindow *dialog = m_activeDialogs[--topMost];
459     lock.Leave();
460     if (dialog->IsModalDialog())
461     { // we have the topmost modal dialog
462       if (!dialog->IsAnimating(ANIM_TYPE_WINDOW_CLOSE))
463       {
464         bool fallThrough = (dialog->GetID() == WINDOW_DIALOG_FULLSCREEN_INFO);
465         if (dialog->OnAction(action))
466           return true;
467         // dialog didn't want the action - we'd normally return false
468         // but for some dialogs we want to drop the actions through
469         if (fallThrough)
470           break;
471         return false;
472       }
473       return true; // do nothing with the action until the anim is finished
474     }
475     // music or video overlay are handled as a special case, as they're modeless, but we allow
476     // clicking on them with the mouse.
477     if (action.IsMouse() && (dialog->GetID() == WINDOW_VIDEO_OVERLAY ||
478                              dialog->GetID() == WINDOW_MUSIC_OVERLAY))
479     {
480       if (dialog->OnAction(action))
481         return true;
482     }
483     lock.Enter();
484     if (topMost > m_activeDialogs.size())
485       topMost = m_activeDialogs.size();
486   }
487   lock.Leave();
488   CGUIWindow* window = GetWindow(GetActiveWindow());
489   if (window)
490     return window->OnAction(action);
491   return false;
492 }
493
494 bool RenderOrderSortFunction(CGUIWindow *first, CGUIWindow *second)
495 {
496   return first->GetRenderOrder() < second->GetRenderOrder();
497 }
498
499 void CGUIWindowManager::Render()
500 {
501   assert(g_application.IsCurrentThread());
502   CSingleLock lock(g_graphicsContext);
503   CGUIWindow* pWindow = GetWindow(GetActiveWindow());
504   if (pWindow)
505   {
506     pWindow->ClearBackground();
507     pWindow->Render();
508   }
509
510   // we render the dialogs based on their render order.
511   vector<CGUIWindow *> renderList = m_activeDialogs;
512   stable_sort(renderList.begin(), renderList.end(), RenderOrderSortFunction);
513   
514   for (iDialog it = renderList.begin(); it != renderList.end(); ++it)
515   {
516     if ((*it)->IsDialogRunning())
517       (*it)->Render();
518   }
519 }
520
521 void CGUIWindowManager::FrameMove()
522 {
523   assert(g_application.IsCurrentThread());
524   CSingleLock lock(g_graphicsContext);
525
526   if(m_iNested == 0)
527   {
528     // delete any windows queued for deletion
529     for(iDialog it = m_deleteWindows.begin(); it != m_deleteWindows.end(); it++)
530     {
531       // Free any window resources
532       (*it)->FreeResources(true);
533       delete *it;
534     }
535     m_deleteWindows.clear();
536   }
537
538   CGUIWindow* pWindow = GetWindow(GetActiveWindow());
539   if (pWindow)
540     pWindow->FrameMove();
541   // update any dialogs - we take a copy of the vector as some dialogs may close themselves
542   // during this call
543   vector<CGUIWindow *> dialogs = m_activeDialogs;
544   for (iDialog it = dialogs.begin(); it != dialogs.end(); ++it)
545     (*it)->FrameMove();
546 }
547
548 CGUIWindow* CGUIWindowManager::GetWindow(int id) const
549 {
550   if (id == WINDOW_INVALID)
551   {
552     return NULL;
553   }
554
555   CSingleLock lock(g_graphicsContext);
556   WindowMap::const_iterator it = m_mapWindows.find(id);
557   if (it != m_mapWindows.end())
558     return (*it).second;
559   return NULL;
560 }
561
562 // Shows and hides modeless dialogs as necessary.
563 void CGUIWindowManager::UpdateModelessVisibility()
564 {
565   CSingleLock lock(g_graphicsContext);
566   for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); it++)
567   {
568     CGUIWindow *pWindow = (*it).second;
569     if (pWindow && pWindow->IsDialog() && pWindow->GetVisibleCondition())
570     {
571       if (g_infoManager.GetBool(pWindow->GetVisibleCondition(), GetActiveWindow()))
572         ((CGUIDialog *)pWindow)->Show();
573       else
574         ((CGUIDialog *)pWindow)->Close();
575     }
576   }
577 }
578
579 void CGUIWindowManager::Process(bool renderOnly /*= false*/)
580 {
581   if (g_application.IsCurrentThread() && m_pCallback)
582   {
583     m_iNested++;
584     if (!renderOnly)
585     {
586       m_pCallback->Process();
587       m_pCallback->FrameMove();
588     }
589     m_pCallback->Render();
590     m_iNested--;
591   }
592 }
593
594 void CGUIWindowManager::SetCallback(IWindowManagerCallback& callback)
595 {
596   m_pCallback = &callback;
597 }
598
599 void CGUIWindowManager::DeInitialize()
600 {
601   CSingleLock lock(g_graphicsContext);
602   for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); it++)
603   {
604     CGUIWindow* pWindow = (*it).second;
605     if (IsWindowActive(it->first))
606     {
607       pWindow->DisableAnimations();
608       CGUIMessage msg(GUI_MSG_WINDOW_DEINIT, 0, 0);
609       pWindow->OnMessage(msg);
610     }
611     pWindow->ResetControlStates();
612     pWindow->FreeResources(true);
613   }
614   UnloadNotOnDemandWindows();
615
616   m_vecMsgTargets.erase( m_vecMsgTargets.begin(), m_vecMsgTargets.end() );
617
618   // destroy our custom windows...
619   for (int i = 0; i < (int)m_vecCustomWindows.size(); i++)
620   {
621     CGUIWindow *pWindow = m_vecCustomWindows[i];
622     Remove(pWindow->GetID());
623     delete pWindow;
624   }
625
626   // clear our vectors of windows
627   m_vecCustomWindows.clear();
628   m_activeDialogs.clear();
629 }
630
631 /// \brief Route to a window
632 /// \param pWindow Window to route to
633 void CGUIWindowManager::RouteToWindow(CGUIWindow* dialog)
634 {
635   CSingleLock lock(g_graphicsContext);
636   // Just to be sure: Unroute this window,
637   // #we may have routed to it before
638   RemoveDialog(dialog->GetID());
639
640   m_activeDialogs.push_back(dialog);
641 }
642
643 /// \brief Unroute window
644 /// \param id ID of the window routed
645 void CGUIWindowManager::RemoveDialog(int id)
646 {
647   CSingleLock lock(g_graphicsContext);
648   for (iDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
649   {
650     if ((*it)->GetID() == id)
651     {
652       m_activeDialogs.erase(it);
653       return;
654     }
655   }
656 }
657
658 bool CGUIWindowManager::HasModalDialog() const
659 {
660   CSingleLock lock(g_graphicsContext);
661   for (ciDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
662   {
663     CGUIWindow *window = *it;
664     if (window->IsModalDialog())
665     { // have a modal window
666       if (!window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE))
667         return true;
668     }
669   }
670   return false;
671 }
672
673 bool CGUIWindowManager::HasDialogOnScreen() const
674 {
675   return (m_activeDialogs.size() > 0);
676 }
677
678 /// \brief Get the ID of the top most routed window
679 /// \return id ID of the window or WINDOW_INVALID if no routed window available
680 int CGUIWindowManager::GetTopMostModalDialogID() const
681 {
682   CSingleLock lock(g_graphicsContext);
683   for (crDialog it = m_activeDialogs.rbegin(); it != m_activeDialogs.rend(); ++it)
684   {
685     CGUIWindow *dialog = *it;
686     if (dialog->IsModalDialog())
687     { // have a modal window
688       return dialog->GetID();
689     }
690   }
691   return WINDOW_INVALID;
692 }
693
694 void CGUIWindowManager::SendThreadMessage(CGUIMessage& message)
695 {
696   CSingleLock lock(m_critSection);
697
698   CGUIMessage* msg = new CGUIMessage(message);
699   m_vecThreadMessages.push_back( pair<CGUIMessage*,int>(msg,0) );
700 }
701
702 void CGUIWindowManager::SendThreadMessage(CGUIMessage& message, int window)
703 {
704   CSingleLock lock(m_critSection);
705
706   CGUIMessage* msg = new CGUIMessage(message);
707   m_vecThreadMessages.push_back( pair<CGUIMessage*,int>(msg,window) );
708 }
709
710 void CGUIWindowManager::DispatchThreadMessages()
711 {
712   CSingleLock lock(m_critSection);
713   vector< pair<CGUIMessage*,int> > messages(m_vecThreadMessages);
714   m_vecThreadMessages.erase(m_vecThreadMessages.begin(), m_vecThreadMessages.end());
715   lock.Leave();
716
717   while ( messages.size() > 0 )
718   {
719     vector< pair<CGUIMessage*,int> >::iterator it = messages.begin();
720     CGUIMessage* pMsg = it->first;
721     int window = it->second;
722     // first remove the message from the queue,
723     // else the message could be processed more then once
724     it = messages.erase(it);
725
726     if (window)
727       SendMessage( *pMsg, window );
728     else
729       SendMessage( *pMsg );
730     delete pMsg;
731   }
732 }
733
734 void CGUIWindowManager::AddMsgTarget( IMsgTargetCallback* pMsgTarget )
735 {
736   m_vecMsgTargets.push_back( pMsgTarget );
737 }
738
739 int CGUIWindowManager::GetActiveWindow() const
740 {
741   if (!m_windowHistory.empty())
742     return m_windowHistory.top();
743   return WINDOW_INVALID;
744 }
745
746 // same as GetActiveWindow() except it first grabs dialogs
747 int CGUIWindowManager::GetFocusedWindow() const
748 {
749   int dialog = GetTopMostModalDialogID();
750   if (dialog != WINDOW_INVALID)
751     return dialog;
752
753   return GetActiveWindow();
754 }
755
756 bool CGUIWindowManager::IsWindowActive(int id, bool ignoreClosing /* = true */) const
757 {
758   // mask out multiple instances of the same window
759   id &= WINDOW_ID_MASK;
760   if ((GetActiveWindow() & WINDOW_ID_MASK) == id) return true;
761   // run through the dialogs
762   CSingleLock lock(g_graphicsContext);
763   for (ciDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
764   {
765     CGUIWindow *window = *it;
766     if ((window->GetID() & WINDOW_ID_MASK) == id && (!ignoreClosing || !window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE)))
767       return true;
768   }
769   return false; // window isn't active
770 }
771
772 bool CGUIWindowManager::IsWindowActive(const CStdString &xmlFile, bool ignoreClosing /* = true */) const
773 {
774   CSingleLock lock(g_graphicsContext);
775   CGUIWindow *window = GetWindow(GetActiveWindow());
776   if (window && CUtil::GetFileName(window->GetProperty("xmlfile")).Equals(xmlFile)) return true;
777   // run through the dialogs
778   for (ciDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
779   {
780     CGUIWindow *window = *it;
781     if (CUtil::GetFileName(window->GetProperty("xmlfile")).Equals(xmlFile) && (!ignoreClosing || !window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE)))
782       return true;
783   }
784   return false; // window isn't active
785 }
786
787 bool CGUIWindowManager::IsWindowVisible(int id) const
788 {
789   return IsWindowActive(id, false);
790 }
791
792 bool CGUIWindowManager::IsWindowVisible(const CStdString &xmlFile) const
793 {
794   return IsWindowActive(xmlFile, false);
795 }
796
797 void CGUIWindowManager::LoadNotOnDemandWindows()
798 {
799   CSingleLock lock(g_graphicsContext);
800   for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); it++)
801   {
802     CGUIWindow *pWindow = (*it).second;
803     if (!pWindow ->GetLoadOnDemand())
804     {
805       pWindow->FreeResources(true);
806       pWindow->Initialize();
807     }
808   }
809 }
810
811 void CGUIWindowManager::UnloadNotOnDemandWindows()
812 {
813   CSingleLock lock(g_graphicsContext);
814   for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); it++)
815   {
816     CGUIWindow *pWindow = (*it).second;
817     if (!pWindow->GetLoadOnDemand())
818     {
819       pWindow->FreeResources(true);
820     }
821   }
822 }
823
824 bool CGUIWindowManager::IsOverlayAllowed() const
825 {
826   if (GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO ||
827       GetActiveWindow() == WINDOW_SCREENSAVER)
828     return false;
829   return m_bShowOverlay;
830 }
831
832 void CGUIWindowManager::ShowOverlay(CGUIWindow::OVERLAY_STATE state)
833 {
834   if (state != CGUIWindow::OVERLAY_STATE_PARENT_WINDOW)
835     m_bShowOverlay = state == CGUIWindow::OVERLAY_STATE_SHOWN;
836 }
837
838 void CGUIWindowManager::HideOverlay(CGUIWindow::OVERLAY_STATE state)
839 {
840   if (state == CGUIWindow::OVERLAY_STATE_HIDDEN)
841     m_bShowOverlay = false;
842 }
843
844 void CGUIWindowManager::AddToWindowHistory(int newWindowID)
845 {
846   // Check the window stack to see if this window is in our history,
847   // and if so, pop all the other windows off the stack so that we
848   // always have a predictable "Back" behaviour for each window
849   stack<int> historySave = m_windowHistory;
850   while (historySave.size())
851   {
852     if (historySave.top() == newWindowID)
853       break;
854     historySave.pop();
855   }
856   if (!historySave.empty())
857   { // found window in history
858     m_windowHistory = historySave;
859   }
860   else
861   { // didn't find window in history - add it to the stack
862     m_windowHistory.push(newWindowID);
863   }
864 }
865
866 void CGUIWindowManager::GetActiveModelessWindows(vector<int> &ids)
867 {
868   // run through our modeless windows, and construct a vector of them
869   // useful for saving and restoring the modeless windows on skin change etc.
870   CSingleLock lock(g_graphicsContext);
871   for (iDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
872   {
873     if (!(*it)->IsModalDialog())
874       ids.push_back((*it)->GetID());
875   }
876 }
877
878 CGUIWindow *CGUIWindowManager::GetTopMostDialog() const
879 {
880   CSingleLock lock(g_graphicsContext);
881   // find the window with the lowest render order
882   vector<CGUIWindow *> renderList = m_activeDialogs;
883   stable_sort(renderList.begin(), renderList.end(), RenderOrderSortFunction);
884
885   if (!renderList.size())
886     return NULL;
887
888   // return the last window in the list
889   return *renderList.rbegin();
890 }
891
892 bool CGUIWindowManager::IsWindowTopMost(int id) const
893 {
894   CGUIWindow *topMost = GetTopMostDialog();
895   if (topMost && (topMost->GetID() & WINDOW_ID_MASK) == id)
896     return true;
897   return false;
898 }
899
900 bool CGUIWindowManager::IsWindowTopMost(const CStdString &xmlFile) const
901 {
902   CGUIWindow *topMost = GetTopMostDialog();
903   if (topMost && CUtil::GetFileName(topMost->GetProperty("xmlfile")).Equals(xmlFile))
904     return true;
905   return false;
906 }
907
908 void CGUIWindowManager::ClearWindowHistory()
909 {
910   while (m_windowHistory.size())
911     m_windowHistory.pop();
912 }
913
914 #ifdef _DEBUG
915 void CGUIWindowManager::DumpTextureUse()
916 {
917   CGUIWindow* pWindow = GetWindow(GetActiveWindow());
918   if (pWindow)
919     pWindow->DumpTextureUse();
920
921   CSingleLock lock(g_graphicsContext);
922   for (iDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
923   {
924     if ((*it)->IsDialogRunning())
925       (*it)->DumpTextureUse();
926   }
927 }
928 #endif