1 /*****************************************************************************
2  * vout_manager.cpp
3  *****************************************************************************
4  * Copyright (C) 2009 the VideoLAN team
5  * $Id: e555e5e6f9acae915ce761b166a4bb9490abc490 $
6  *
7  * Authors: Erwan Tulou <brezhoneg1 at yahoo.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23 
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 
28 #include "vout_manager.hpp"
29 #include "vlcproc.hpp"
30 #include "os_factory.hpp"
31 
32 
33 
instance(intf_thread_t * pIntf)34 VoutManager *VoutManager::instance( intf_thread_t *pIntf )
35 {
36     if( pIntf->p_sys->p_voutManager == NULL )
37     {
38         pIntf->p_sys->p_voutManager = new VoutManager( pIntf );
39     }
40 
41     return pIntf->p_sys->p_voutManager;
42 }
43 
44 
destroy(intf_thread_t * pIntf)45 void VoutManager::destroy( intf_thread_t *pIntf )
46 {
47     delete pIntf->p_sys->p_voutManager;
48     pIntf->p_sys->p_voutManager = NULL;
49 }
50 
51 
VoutManager(intf_thread_t * pIntf)52 VoutManager::VoutManager( intf_thread_t *pIntf ): SkinObject( pIntf ),
53      m_pCtrlVideoVec(), m_pCtrlVideoVecBackup(), m_SavedWndVec(),
54      m_pVoutMainWindow( NULL ), m_pFscWindow( NULL )
55 {
56     m_pVoutMainWindow = new VoutMainWindow( getIntf() );
57 
58     OSFactory *pOsFactory = OSFactory::instance( getIntf() );
59     int width = pOsFactory->getScreenWidth();
60     int height = pOsFactory->getScreenHeight();
61 
62     m_pVoutMainWindow->move( 0, 0 );
63     m_pVoutMainWindow->resize( width, height );
64 
65     VarBool &rFullscreen = VlcProc::instance( getIntf() )->getFullscreenVar();
66     rFullscreen.addObserver( this );
67 }
68 
69 
~VoutManager()70 VoutManager::~VoutManager( )
71 {
72     VarBool &rFullscreen = VlcProc::instance( getIntf() )->getFullscreenVar();
73     rFullscreen.delObserver( this );
74 
75     delete m_pVoutMainWindow;
76 }
77 
78 
registerCtrlVideo(CtrlVideo * p_CtrlVideo)79 void VoutManager::registerCtrlVideo( CtrlVideo* p_CtrlVideo )
80 {
81     m_pCtrlVideoVec.push_back( p_CtrlVideo );
82 }
83 
84 
registerFSC(FscWindow * p_Win)85 void VoutManager::registerFSC( FscWindow* p_Win )
86 {
87     m_pFscWindow = p_Win;
88 }
89 
90 
saveVoutConfig()91 void VoutManager::saveVoutConfig( )
92 {
93     // Save width/height to be consistent across themes
94     // and detach Video Controls
95     std::vector<SavedWnd>::iterator it;
96     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); ++it )
97     {
98         if( it->pCtrlVideo )
99         {
100             // detach vout thread from VideoControl
101             it->pCtrlVideo->detachVoutWindow( );
102 
103             // memorize width/height before VideoControl is destroyed
104             it->width = it->pCtrlVideo->getPosition()->getWidth();
105             it->height = it->pCtrlVideo->getPosition()->getHeight();
106             it->pCtrlVideo = NULL;
107        }
108     }
109 
110     // Create a backup copy and reset original for new theme
111     m_pCtrlVideoVecBackup = m_pCtrlVideoVec;
112     m_pCtrlVideoVec.clear();
113 }
114 
115 
restoreVoutConfig(bool b_success)116 void VoutManager::restoreVoutConfig( bool b_success )
117 {
118     if( !b_success )
119     {
120         // loading new theme failed, restoring previous theme
121         m_pCtrlVideoVec = m_pCtrlVideoVecBackup;
122     }
123 
124     // reattach vout(s) to Video Controls
125     std::vector<SavedWnd>::iterator it;
126     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); ++it )
127     {
128         CtrlVideo* pCtrlVideo = getBestCtrlVideo();
129         if( pCtrlVideo )
130         {
131             pCtrlVideo->attachVoutWindow( it->pVoutWindow );
132             it->pCtrlVideo = pCtrlVideo;
133         }
134     }
135 }
136 
137 
discardVout(CtrlVideo * pCtrlVideo)138 void VoutManager::discardVout( CtrlVideo* pCtrlVideo )
139 {
140     std::vector<SavedWnd>::iterator it;
141     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); ++it )
142     {
143         if( it->pCtrlVideo == pCtrlVideo )
144         {
145             // detach vout thread from VideoControl
146             it->pCtrlVideo->detachVoutWindow( );
147             it->width = it->pCtrlVideo->getPosition()->getWidth();
148             it->height = it->pCtrlVideo->getPosition()->getHeight();
149             it->pCtrlVideo = NULL;
150             break;
151         }
152     }
153 }
154 
155 
requestVout(CtrlVideo * pCtrlVideo)156 void VoutManager::requestVout( CtrlVideo* pCtrlVideo )
157 {
158     std::vector<SavedWnd>::iterator it;
159     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); ++it )
160     {
161         if( it->pCtrlVideo == NULL )
162         {
163             pCtrlVideo->attachVoutWindow( it->pVoutWindow,
164                                           it->width, it->height );
165             it->pCtrlVideo = pCtrlVideo;
166             break;
167         }
168     }
169 }
170 
171 
getBestCtrlVideo()172 CtrlVideo* VoutManager::getBestCtrlVideo( )
173 {
174     std::vector<CtrlVideo*>::const_iterator it;
175 
176     // first, look up a video control that is visible and unused
177     for( it = m_pCtrlVideoVec.begin(); it != m_pCtrlVideoVec.end(); ++it )
178     {
179         if( (*it)->isUseable() && !(*it)->isUsed() )
180         {
181             return (*it);
182         }
183     }
184 
185     return NULL;
186 }
187 
188 
189 
190 // Functions called by window provider
191 // ///////////////////////////////////
192 
acceptWnd(vout_window_t * pWnd,int width,int height)193 void VoutManager::acceptWnd( vout_window_t* pWnd, int width, int height )
194 {
195     // Creation of a dedicated Window per vout thread
196     VoutWindow* pVoutWindow = new VoutWindow( getIntf(), pWnd, width, height,
197                                          (GenericWindow*) m_pVoutMainWindow );
198 
199     // try to find a video Control within the theme
200     CtrlVideo* pCtrlVideo = getBestCtrlVideo();
201     if( pCtrlVideo )
202     {
203         // A Video Control is available
204         // directly attach vout thread to it
205         pCtrlVideo->attachVoutWindow( pVoutWindow );
206     }
207     else
208     {
209         pVoutWindow->setCtrlVideo( NULL );
210     }
211 
212     // save vout characteristics
213     m_SavedWndVec.push_back( SavedWnd( pWnd, pVoutWindow, pCtrlVideo ) );
214 
215     msg_Dbg( pWnd, "New vout : Ctrl = %p, w x h = %ix%i",
216                     (void *)pCtrlVideo, width, height );
217 }
218 
219 
releaseWnd(vout_window_t * pWnd)220 void VoutManager::releaseWnd( vout_window_t* pWnd )
221 {
222     // remove vout thread from savedVec
223     std::vector<SavedWnd>::iterator it;
224     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); ++it )
225     {
226         if( it->pWnd == pWnd )
227         {
228             msg_Dbg( getIntf(), "vout released vout=%p, VideoCtrl=%p",
229                              (void *)pWnd, it->pCtrlVideo );
230 
231             // if a video control was being used, detach from it
232             if( it->pCtrlVideo )
233             {
234                 it->pCtrlVideo->detachVoutWindow( );
235             }
236 
237             // remove resources
238             delete it->pVoutWindow;
239             m_SavedWndVec.erase( it );
240             break;
241         }
242     }
243 
244     // force fullscreen to false so that user regains control
245     VlcProc::instance( getIntf() )->setFullscreenVar( false );
246 }
247 
248 
setSizeWnd(vout_window_t * pWnd,int width,int height)249 void VoutManager::setSizeWnd( vout_window_t *pWnd, int width, int height )
250 {
251    msg_Dbg( pWnd, "setSize (%ix%i) received from vout thread",
252                   width, height );
253 
254    std::vector<SavedWnd>::iterator it;
255    for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); ++it )
256    {
257        if( it->pWnd == pWnd )
258        {
259            VoutWindow* pVoutWindow = it->pVoutWindow;
260 
261            pVoutWindow->setOriginalWidth( width );
262            pVoutWindow->setOriginalHeight( height );
263 
264            CtrlVideo* pCtrlVideo = pVoutWindow->getCtrlVideo();
265            if( pCtrlVideo )
266            {
267                pCtrlVideo->resizeControl( width, height );
268            }
269            break;
270        }
271    }
272 }
273 
274 
setFullscreenWnd(vout_window_t * pWnd,bool b_fullscreen)275 void VoutManager::setFullscreenWnd( vout_window_t *pWnd, bool b_fullscreen )
276 {
277     msg_Dbg( pWnd, "setFullscreen (%i) received from vout thread",
278                    b_fullscreen );
279 
280     // reconfigure the fullscreen window (multiple screens)
281     if( b_fullscreen )
282     {
283         std::vector<SavedWnd>::iterator it;
284         for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); ++it )
285         {
286             if( it->pWnd == pWnd )
287             {
288                 VoutWindow* pVoutWindow = it->pVoutWindow;
289                 configureFullscreen( *pVoutWindow );
290                 break;
291             }
292         }
293     }
294 
295     // set fullscreen
296     VlcProc::instance( getIntf() )->setFullscreenVar( b_fullscreen );
297 }
298 
299 
hideMouseWnd(vout_window_t * pWnd,bool hide)300 void VoutManager::hideMouseWnd( vout_window_t *pWnd, bool hide )
301 {
302     msg_Dbg( pWnd, "hide mouse (%i) received from vout thread", hide );
303     OSFactory *pOsFactory = OSFactory::instance( getIntf() );
304     if( hide )
305         pOsFactory->changeCursor( OSFactory::kNoCursor );
306     else
307         pOsFactory->changeCursor( OSFactory::kDefaultArrow );
308 }
309 
310 
onUpdate(Subject<VarBool> & rVariable,void * arg)311 void VoutManager::onUpdate( Subject<VarBool> &rVariable, void *arg )
312 {
313     (void)arg;
314     VarBool &rFullscreen = VlcProc::instance( getIntf() )->getFullscreenVar();
315     if( &rVariable == &rFullscreen )
316     {
317         if( rFullscreen.get() )
318             m_pVoutMainWindow->show();
319         else
320             m_pVoutMainWindow->hide();
321     }
322 }
323 
324 
configureFullscreen(VoutWindow & rWindow)325 void VoutManager::configureFullscreen( VoutWindow& rWindow )
326 {
327     int numScr = var_InheritInteger( getIntf(), "qt-fullscreen-screennumber" );
328 
329     int x, y, w, h;
330     if( numScr >= 0 )
331     {
332         // select screen requested by user
333         OSFactory *pOsFactory = OSFactory::instance( getIntf() );
334         pOsFactory->getMonitorInfo( numScr, &x, &y, &w, &h );
335     }
336     else
337     {
338         // select screen where display is already occurring
339         rWindow.getMonitorInfo( &x, &y, &w, &h );
340     }
341 
342     // move and resize fullscreen
343     m_pVoutMainWindow->move( x, y );
344     m_pVoutMainWindow->resize( w, h );
345 
346     // ensure the fs controller is also moved
347     if( m_pFscWindow )
348     {
349         m_pFscWindow->moveTo( x, y, w, h );
350     }
351 }
352