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