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