400743187d1a7e34354bb7ce483235f96a14d2ae
[vlc.git] / modules / gui / skins2 / src / vout_manager.cpp
1 /*****************************************************************************
2  * vout_manager.cpp
3  *****************************************************************************
4  * Copyright (C) 2009 the VideoLAN team
5  * $Id$
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 <vlc_vout.h>
29 #include <vlc_window.h>
30
31 #include "vout_manager.hpp"
32 #include "window_manager.hpp"
33 #include "vlcproc.hpp"
34 #include "../commands/async_queue.hpp"
35 #include "../commands/cmd_show_window.hpp"
36 #include "../commands/cmd_resize.hpp"
37
38
39
40 VoutManager *VoutManager::instance( intf_thread_t *pIntf )
41 {
42     if( pIntf->p_sys->p_voutManager == NULL )
43     {
44         pIntf->p_sys->p_voutManager = new VoutManager( pIntf );
45     }
46
47     return pIntf->p_sys->p_voutManager;
48 }
49
50
51 void VoutManager::destroy( intf_thread_t *pIntf )
52 {
53     delete pIntf->p_sys->p_voutManager;
54     pIntf->p_sys->p_voutManager = NULL;
55 }
56
57
58 VoutManager::VoutManager( intf_thread_t *pIntf ): SkinObject( pIntf ),
59      m_pVoutMainWindow( NULL ), m_pCtrlVideoVec(),
60      m_pCtrlVideoVecBackup(), m_SavedVoutVec()
61 {
62     vlc_mutex_init( &vout_lock );
63
64     m_pVoutMainWindow = new VoutMainWindow( getIntf() );
65 }
66
67
68 VoutManager::~VoutManager( )
69 {
70     vlc_mutex_destroy( &vout_lock );
71
72     delete m_pVoutMainWindow;
73 }
74
75
76 void VoutManager::registerCtrlVideo( CtrlVideo* p_CtrlVideo )
77 {
78     m_pCtrlVideoVec.push_back( p_CtrlVideo );
79 }
80
81
82 void VoutManager::saveVoutConfig( )
83 {
84     // Save width/height to be consistent across themes
85     // and detach Video Controls
86     vector<SavedVout>::iterator it;
87     for( it = m_SavedVoutVec.begin(); it != m_SavedVoutVec.end(); it++ )
88     {
89         if( (*it).pCtrlVideo )
90         {
91             // detach vout thread from VideoControl
92             (*it).pCtrlVideo->detachVoutWindow( );
93
94             // memorize width/height before VideoControl is destroyed
95             (*it).width = (*it).pCtrlVideo->getPosition()->getWidth();
96             (*it).height = (*it).pCtrlVideo->getPosition()->getHeight();
97             (*it).pCtrlVideo = NULL;
98        }
99     }
100
101     // Create a backup copy and reset original for new theme
102     m_pCtrlVideoVecBackup = m_pCtrlVideoVec;
103     m_pCtrlVideoVec.clear();
104 }
105
106
107 void VoutManager::restoreVoutConfig( bool b_success )
108 {
109     if( !b_success )
110     {
111         // loading new theme failed, restoring previous theme
112         m_pCtrlVideoVec = m_pCtrlVideoVecBackup;
113     }
114
115     // reattach vout(s) to Video Controls
116     vector<SavedVout>::iterator it;
117     for( it = m_SavedVoutVec.begin(); it != m_SavedVoutVec.end(); it++ )
118     {
119         CtrlVideo* pCtrlVideo = getBestCtrlVideo();
120         if( pCtrlVideo )
121         {
122             pCtrlVideo->attachVoutWindow( (*it).pVoutWindow );
123            (*it).pCtrlVideo = pCtrlVideo;
124         }
125     }
126 }
127
128
129 void VoutManager::discardVout( CtrlVideo* pCtrlVideo )
130 {
131     vector<SavedVout>::iterator it;
132     for( it = m_SavedVoutVec.begin(); it != m_SavedVoutVec.end(); it++ )
133     {
134         if( (*it).pCtrlVideo == pCtrlVideo )
135         {
136             // detach vout thread from VideoControl
137             (*it).pCtrlVideo->detachVoutWindow( );
138             (*it).width = (*it).pCtrlVideo->getPosition()->getWidth();
139             (*it).height = (*it).pCtrlVideo->getPosition()->getHeight();
140             (*it).pCtrlVideo = NULL;
141             break;
142         }
143     }
144 }
145
146
147 void VoutManager::requestVout( CtrlVideo* pCtrlVideo )
148 {
149     vector<SavedVout>::iterator it;
150     for( it = m_SavedVoutVec.begin(); it != m_SavedVoutVec.end(); it++ )
151     {
152         if( (*it).pCtrlVideo == NULL )
153         {
154             pCtrlVideo->attachVoutWindow( (*it).pVoutWindow,
155                                           (*it).width, (*it).height );
156             (*it).pCtrlVideo = pCtrlVideo;
157             break;
158         }
159     }
160 }
161
162
163 CtrlVideo* VoutManager::getBestCtrlVideo( )
164 {
165     // try to find an unused useable VideoControl
166
167     vector<CtrlVideo*>::const_iterator it;
168     for( it = m_pCtrlVideoVec.begin(); it != m_pCtrlVideoVec.end(); it++ )
169     {
170         if( (*it)->isUseable() && !(*it)->isUsed() )
171         {
172             return (*it);
173         }
174     }
175
176     return NULL;
177 }
178
179
180 void* VoutManager::acceptVout( vout_thread_t* pVout, int width, int height )
181 {
182     // Creation of a dedicated Window per vout thread
183     VoutWindow* pVoutWindow = new VoutWindow( getIntf(), pVout, width, height,
184                                          (GenericWindow*) m_pVoutMainWindow );
185
186     void* handle = pVoutWindow->getOSHandle();
187
188     // try to find a video Control within the theme
189     CtrlVideo* pCtrlVideo = getBestCtrlVideo();
190     if( pCtrlVideo )
191     {
192         // A Video Control is available
193         // directly attach vout thread to it
194         pCtrlVideo->attachVoutWindow( pVoutWindow );
195     }
196
197     // save vout characteristics
198     m_SavedVoutVec.push_back( SavedVout( pVout, pVoutWindow, pCtrlVideo ) );
199
200     msg_Dbg( getIntf(), "New incoming vout=0x%p, handle=0x%p, VideoCtrl=0x%p",
201                         pVout, handle, pCtrlVideo );
202
203     return handle;
204 }
205
206
207 // Functions called by window provider
208 // ///////////////////////////////////
209
210 void *VoutManager::getWindow( intf_thread_t *pIntf, vout_window_t *pWnd )
211 {
212     // Theme may have been destroyed
213     if( !pIntf->p_sys->p_theme )
214         return NULL;
215
216     VoutManager *pThis = pIntf->p_sys->p_voutManager;
217
218     vout_thread_t* pVout = pWnd->vout;
219     int width = (int)pWnd->width;
220     int height = (int)pWnd->height;
221
222     pThis->lockVout();
223
224     void* handle = pThis->acceptVout( pVout, width, height );
225
226     pThis->unlockVout();
227
228     return handle;
229 }
230
231
232 void VoutManager::releaseWindow( intf_thread_t *pIntf, vout_window_t *pWnd )
233 {
234     VoutManager *pThis = pIntf->p_sys->p_voutManager;
235
236     // Theme may have been destroyed
237     if( !pIntf->p_sys->p_theme )
238         return;
239
240     vout_thread_t* pVout = pWnd->vout;
241
242     pThis->lockVout();
243
244     // remove vout thread from savedVec
245     vector<SavedVout>::iterator it;
246     for( it = pThis->m_SavedVoutVec.begin(); it != pThis->m_SavedVoutVec.end(); it++ )
247     {
248         if( (*it).pVout == pVout )
249         {
250             msg_Dbg( pIntf, "vout released vout=0x%p, VideoCtrl=0x%p",
251                              pVout, (*it).pCtrlVideo );
252
253             // if a video control was being used, detach from it
254             if( (*it).pCtrlVideo )
255             {
256                 (*it).pCtrlVideo->detachVoutWindow( );
257             }
258
259             // remove resources
260             delete (*it).pVoutWindow;
261             pThis->m_SavedVoutVec.erase( it );
262             break;
263         }
264     }
265
266     pThis->unlockVout();
267 }
268
269
270 int VoutManager::controlWindow( struct vout_window_t *pWnd,
271                             int query, va_list args )
272 {
273     intf_thread_t *pIntf = (intf_thread_t *)pWnd->p_private;
274     VoutManager *pThis = pIntf->p_sys->p_voutManager;
275     vout_thread_t* pVout = pWnd->vout;
276
277     switch( query )
278     {
279         case VOUT_SET_SIZE:
280         {
281             unsigned int i_width  = va_arg( args, unsigned int );
282             unsigned int i_height = va_arg( args, unsigned int );
283
284             if( i_width && i_height )
285             {
286                 pThis->lockVout();
287
288                 vector<SavedVout>::iterator it;
289                 for( it = pThis->m_SavedVoutVec.begin();
290                      it != pThis->m_SavedVoutVec.end(); it++ )
291                 {
292                     if( (*it).pVout == pVout )
293                     {
294                         // Post a vout resize command
295                         CmdResizeVout *pCmd =
296                             new CmdResizeVout( pThis->getIntf(),
297                                                (*it).pVoutWindow,
298                                                (int)i_width, (int)i_height );
299                         AsyncQueue *pQueue =
300                             AsyncQueue::instance( pThis->getIntf() );
301                         pQueue->push( CmdGenericPtr( pCmd ) );
302                         break;
303                     }
304                 }
305
306                 pThis->unlockVout();
307             }
308         }
309
310         default:
311             msg_Dbg( pWnd, "control query not supported" );
312             break;
313     }
314
315     return VLC_SUCCESS;
316 }
317