]> git.sesse.net Git - vlc/blob - modules/gui/skins2/src/vout_manager.cpp
12cbf176534f8e424f46df93f9717b58228fd03e
[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
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 #include "../commands/cmd_voutwindow.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_SavedWndVec()
61 {
62     m_pVoutMainWindow = new VoutMainWindow( getIntf() );
63 }
64
65
66 VoutManager::~VoutManager( )
67 {
68     delete m_pVoutMainWindow;
69 }
70
71
72 void VoutManager::registerCtrlVideo( CtrlVideo* p_CtrlVideo )
73 {
74     m_pCtrlVideoVec.push_back( p_CtrlVideo );
75 }
76
77
78 void VoutManager::saveVoutConfig( )
79 {
80     // Save width/height to be consistent across themes
81     // and detach Video Controls
82     vector<SavedWnd>::iterator it;
83     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); it++ )
84     {
85         if( (*it).pCtrlVideo )
86         {
87             // detach vout thread from VideoControl
88             (*it).pCtrlVideo->detachVoutWindow( );
89
90             // memorize width/height before VideoControl is destroyed
91             (*it).width = (*it).pCtrlVideo->getPosition()->getWidth();
92             (*it).height = (*it).pCtrlVideo->getPosition()->getHeight();
93             (*it).pCtrlVideo = NULL;
94        }
95     }
96
97     // Create a backup copy and reset original for new theme
98     m_pCtrlVideoVecBackup = m_pCtrlVideoVec;
99     m_pCtrlVideoVec.clear();
100 }
101
102
103 void VoutManager::restoreVoutConfig( bool b_success )
104 {
105     if( !b_success )
106     {
107         // loading new theme failed, restoring previous theme
108         m_pCtrlVideoVec = m_pCtrlVideoVecBackup;
109     }
110
111     // reattach vout(s) to Video Controls
112     vector<SavedWnd>::iterator it;
113     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); it++ )
114     {
115         CtrlVideo* pCtrlVideo = getBestCtrlVideo();
116         if( pCtrlVideo )
117         {
118             pCtrlVideo->attachVoutWindow( (*it).pVoutWindow );
119            (*it).pCtrlVideo = pCtrlVideo;
120         }
121     }
122 }
123
124
125 void VoutManager::discardVout( CtrlVideo* pCtrlVideo )
126 {
127     vector<SavedWnd>::iterator it;
128     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); it++ )
129     {
130         if( (*it).pCtrlVideo == pCtrlVideo )
131         {
132             // detach vout thread from VideoControl
133             (*it).pCtrlVideo->detachVoutWindow( );
134             (*it).width = (*it).pCtrlVideo->getPosition()->getWidth();
135             (*it).height = (*it).pCtrlVideo->getPosition()->getHeight();
136             (*it).pCtrlVideo = NULL;
137             break;
138         }
139     }
140 }
141
142
143 void VoutManager::requestVout( CtrlVideo* pCtrlVideo )
144 {
145     vector<SavedWnd>::iterator it;
146     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); it++ )
147     {
148         if( (*it).pCtrlVideo == NULL )
149         {
150             pCtrlVideo->attachVoutWindow( (*it).pVoutWindow,
151                                           (*it).width, (*it).height );
152             (*it).pCtrlVideo = pCtrlVideo;
153             break;
154         }
155     }
156 }
157
158
159 CtrlVideo* VoutManager::getBestCtrlVideo( )
160 {
161     // try to find an unused useable VideoControl
162
163     vector<CtrlVideo*>::const_iterator it;
164     for( it = m_pCtrlVideoVec.begin(); it != m_pCtrlVideoVec.end(); it++ )
165     {
166         if( (*it)->isUseable() && !(*it)->isUsed() )
167         {
168             return (*it);
169         }
170     }
171
172     return NULL;
173 }
174
175
176 void* VoutManager::acceptWnd( vout_window_t* pWnd )
177 {
178     int width = (int)pWnd->cfg->width;
179     int height = (int)pWnd->cfg->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( pWnd, "New vout : handle = %p, Ctrl = %p, w x h = %dx%d",
200                     handle, pCtrlVideo, width, height );
201
202     return handle;
203 }
204
205
206 void VoutManager::releaseWnd( vout_window_t *pWnd )
207 {
208     // remove vout thread from savedVec
209     vector<SavedWnd>::iterator it;
210     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); it++ )
211     {
212         if( (*it).pWnd == pWnd )
213         {
214             msg_Dbg( getIntf(), "vout released vout=%p, VideoCtrl=%p",
215                              pWnd, (*it).pCtrlVideo );
216
217             // if a video control was being used, detach from it
218             if( (*it).pCtrlVideo )
219             {
220                 (*it).pCtrlVideo->detachVoutWindow( );
221             }
222
223             // remove resources
224             delete (*it).pVoutWindow;
225             m_SavedWndVec.erase( it );
226             break;
227         }
228     }
229 }
230
231
232 void VoutManager::setSizeWnd( vout_window_t *pWnd, int width, int height )
233 {
234    msg_Dbg( pWnd, "setSize (%dx%d) received from vout threadr",
235                   width, height );
236
237    vector<SavedWnd>::iterator it;
238    for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); it++ )
239    {
240        if( (*it).pWnd == pWnd )
241        {
242            VoutWindow* pVoutWindow = (*it).pVoutWindow;
243
244            pVoutWindow->setOriginalWidth( width );
245            pVoutWindow->setOriginalHeight( height );
246
247            CtrlVideo* pCtrlVideo = pVoutWindow->getCtrlVideo();
248            if( pCtrlVideo )
249            {
250                pCtrlVideo->resizeControl( width, height );
251            }
252            break;
253        }
254    }
255 }
256
257 void VoutManager::setFullscreenWnd( vout_window_t *pWnd, bool b_fullscreen )
258 {
259    msg_Dbg( pWnd, "setFullscreen (%d) received from vout thread",
260                    b_fullscreen ? 1 : 0 );
261
262    vector<SavedWnd>::iterator it;
263    for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); it++ )
264    {
265        if( (*it).pWnd == pWnd )
266        {
267            VoutWindow* pVoutWindow = (*it).pVoutWindow;
268
269            pVoutWindow->setFullscreen( b_fullscreen );
270            break;
271        }
272     }
273 }
274
275 // Functions called by window provider
276 // ///////////////////////////////////
277
278 void *VoutManager::getWindow( intf_thread_t *pIntf, vout_window_t *pWnd )
279 {
280     // Theme may have been destroyed
281     if( !pIntf->p_sys->p_theme )
282         return NULL;
283
284     vlc_mutex_lock( &pIntf->p_sys->vout_lock );
285     pIntf->p_sys->b_vout_ready = false;
286     pIntf->p_sys->handle = NULL;
287
288     CmdNewVoutWindow *pCmd =
289         new CmdNewVoutWindow( pIntf, pWnd );
290
291     AsyncQueue *pQueue = AsyncQueue::instance( pIntf );
292     pQueue->push( CmdGenericPtr( pCmd ), false );
293
294     while( !pIntf->p_sys->b_vout_ready )
295         vlc_cond_wait( &pIntf->p_sys->vout_wait, &pIntf->p_sys->vout_lock );
296
297     void* handle = pIntf->p_sys->handle;
298     vlc_mutex_unlock( &pIntf->p_sys->vout_lock );
299
300     return handle;
301 }
302
303
304 void VoutManager::releaseWindow( intf_thread_t *pIntf, vout_window_t *pWnd )
305 {
306     vlc_mutex_lock( &pIntf->p_sys->vout_lock );
307     pIntf->p_sys->b_vout_ready = false;
308
309     CmdReleaseVoutWindow *pCmd =
310         new CmdReleaseVoutWindow( pIntf, pWnd );
311
312     AsyncQueue *pQueue = AsyncQueue::instance( pIntf );
313     pQueue->push( CmdGenericPtr( pCmd ), false );
314
315     while( !pIntf->p_sys->b_vout_ready )
316         vlc_cond_wait( &pIntf->p_sys->vout_wait, &pIntf->p_sys->vout_lock );
317
318     vlc_mutex_unlock( &pIntf->p_sys->vout_lock );
319 }
320
321
322 int VoutManager::controlWindow( struct vout_window_t *pWnd,
323                             int query, va_list args )
324 {
325     intf_thread_t *pIntf = (intf_thread_t *)pWnd->sys;
326     VoutManager *pThis = pIntf->p_sys->p_voutManager;
327
328     switch( query )
329     {
330         case VOUT_WINDOW_SET_SIZE:
331         {
332             unsigned int i_width  = va_arg( args, unsigned int );
333             unsigned int i_height = va_arg( args, unsigned int );
334
335             if( i_width && i_height )
336             {
337                 // Post a vout resize command
338                 CmdResizeVout *pCmd =
339                     new CmdResizeVout( pThis->getIntf(),
340                                         pWnd, (int)i_width, (int)i_height );
341                 AsyncQueue *pQueue =
342                    AsyncQueue::instance( pThis->getIntf() );
343                 pQueue->push( CmdGenericPtr( pCmd ) );
344             }
345             return VLC_SUCCESS;
346         }
347
348         case VOUT_WINDOW_SET_FULLSCREEN:
349         {
350             bool b_fullscreen = va_arg( args, int );
351
352             // Post a vout resize command
353             CmdSetFullscreen* pCmd =
354                 new CmdSetFullscreen( pThis->getIntf(), pWnd, b_fullscreen );
355
356             AsyncQueue *pQueue = AsyncQueue::instance( pThis->getIntf() );
357             pQueue->push( CmdGenericPtr( pCmd ) );
358
359             return VLC_SUCCESS;
360         }
361
362         default:
363             msg_Dbg( pWnd, "control query not supported" );
364             return VLC_EGENERIC;
365     }
366 }
367