]> git.sesse.net Git - vlc/blob - modules/gui/skins2/src/vout_manager.cpp
skins2: add support for --[no]-video-on-top (fix #685)
[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_vout_display.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 #include "../commands/cmd_voutwindow.hpp"
38 #include "../commands/cmd_on_top.hpp"
39
40
41
42 VoutManager *VoutManager::instance( intf_thread_t *pIntf )
43 {
44     if( pIntf->p_sys->p_voutManager == NULL )
45     {
46         pIntf->p_sys->p_voutManager = new VoutManager( pIntf );
47     }
48
49     return pIntf->p_sys->p_voutManager;
50 }
51
52
53 void VoutManager::destroy( intf_thread_t *pIntf )
54 {
55     delete pIntf->p_sys->p_voutManager;
56     pIntf->p_sys->p_voutManager = NULL;
57 }
58
59
60 VoutManager::VoutManager( intf_thread_t *pIntf ): SkinObject( pIntf ),
61      m_pVoutMainWindow( NULL ), m_pFscWindow( NULL ), m_pCtrlVideoVec(),
62      m_pCtrlVideoVecBackup(), m_SavedWndVec()
63 {
64     m_pVoutMainWindow = new VoutMainWindow( getIntf() );
65
66     OSFactory *pOsFactory = OSFactory::instance( getIntf() );
67     int width = pOsFactory->getScreenWidth();
68     int height = pOsFactory->getScreenHeight();
69
70     m_pVoutMainWindow->move( 0, 0 );
71     m_pVoutMainWindow->resize( width, height );
72 }
73
74
75 VoutManager::~VoutManager( )
76 {
77     delete m_pVoutMainWindow;
78 }
79
80
81 void VoutManager::registerCtrlVideo( CtrlVideo* p_CtrlVideo )
82 {
83     m_pCtrlVideoVec.push_back( p_CtrlVideo );
84 }
85
86
87 void VoutManager::registerFSC( TopWindow* p_Win )
88 {
89     m_pFscWindow = p_Win;
90
91     int x = p_Win->getLeft();
92     int y = p_Win->getTop();
93     p_Win->setParent( m_pVoutMainWindow, x , y, 0, 0 );
94 }
95
96
97 void VoutManager::saveVoutConfig( )
98 {
99     // Save width/height to be consistent across themes
100     // and detach Video Controls
101     vector<SavedWnd>::iterator it;
102     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); it++ )
103     {
104         if( (*it).pCtrlVideo )
105         {
106             // detach vout thread from VideoControl
107             (*it).pCtrlVideo->detachVoutWindow( );
108
109             // memorize width/height before VideoControl is destroyed
110             (*it).width = (*it).pCtrlVideo->getPosition()->getWidth();
111             (*it).height = (*it).pCtrlVideo->getPosition()->getHeight();
112             (*it).pCtrlVideo = NULL;
113        }
114     }
115
116     // Create a backup copy and reset original for new theme
117     m_pCtrlVideoVecBackup = m_pCtrlVideoVec;
118     m_pCtrlVideoVec.clear();
119 }
120
121
122 void VoutManager::restoreVoutConfig( bool b_success )
123 {
124     if( !b_success )
125     {
126         // loading new theme failed, restoring previous theme
127         m_pCtrlVideoVec = m_pCtrlVideoVecBackup;
128     }
129
130     // reattach vout(s) to Video Controls
131     vector<SavedWnd>::iterator it;
132     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); it++ )
133     {
134         CtrlVideo* pCtrlVideo = getBestCtrlVideo();
135         if( pCtrlVideo )
136         {
137             pCtrlVideo->attachVoutWindow( (*it).pVoutWindow );
138            (*it).pCtrlVideo = pCtrlVideo;
139         }
140     }
141 }
142
143
144 void VoutManager::discardVout( CtrlVideo* pCtrlVideo )
145 {
146     vector<SavedWnd>::iterator it;
147     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); it++ )
148     {
149         if( (*it).pCtrlVideo == pCtrlVideo )
150         {
151             // detach vout thread from VideoControl
152             (*it).pCtrlVideo->detachVoutWindow( );
153             (*it).width = (*it).pCtrlVideo->getPosition()->getWidth();
154             (*it).height = (*it).pCtrlVideo->getPosition()->getHeight();
155             (*it).pCtrlVideo = NULL;
156             break;
157         }
158     }
159 }
160
161
162 void VoutManager::requestVout( CtrlVideo* pCtrlVideo )
163 {
164     vector<SavedWnd>::iterator it;
165     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); it++ )
166     {
167         if( (*it).pCtrlVideo == NULL )
168         {
169             pCtrlVideo->attachVoutWindow( (*it).pVoutWindow,
170                                           (*it).width, (*it).height );
171             (*it).pCtrlVideo = pCtrlVideo;
172             break;
173         }
174     }
175 }
176
177
178 CtrlVideo* VoutManager::getBestCtrlVideo( )
179 {
180     // try to find an unused useable VideoControl
181
182     vector<CtrlVideo*>::const_iterator it;
183     for( it = m_pCtrlVideoVec.begin(); it != m_pCtrlVideoVec.end(); it++ )
184     {
185         if( (*it)->isUseable() && !(*it)->isUsed() )
186         {
187             return (*it);
188         }
189     }
190
191     return NULL;
192 }
193
194
195 void* VoutManager::acceptWnd( vout_window_t* pWnd )
196 {
197     int width = (int)pWnd->cfg->width;
198     int height = (int)pWnd->cfg->height;
199
200     // Creation of a dedicated Window per vout thread
201     VoutWindow* pVoutWindow = new VoutWindow( getIntf(), pWnd, width, height,
202                                          (GenericWindow*) m_pVoutMainWindow );
203
204     void* handle = pVoutWindow->getOSHandle();
205
206     // try to find a video Control within the theme
207     CtrlVideo* pCtrlVideo = getBestCtrlVideo();
208     if( pCtrlVideo )
209     {
210         // A Video Control is available
211         // directly attach vout thread to it
212         pCtrlVideo->attachVoutWindow( pVoutWindow );
213     }
214
215     // save vout characteristics
216     m_SavedWndVec.push_back( SavedWnd( pWnd, pVoutWindow, pCtrlVideo ) );
217
218     msg_Dbg( pWnd, "New vout : handle = %p, Ctrl = %p, w x h = %dx%d",
219                     handle, pCtrlVideo, width, height );
220
221     return handle;
222 }
223
224
225 void VoutManager::releaseWnd( vout_window_t *pWnd )
226 {
227     // remove vout thread from savedVec
228     vector<SavedWnd>::iterator it;
229     for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); it++ )
230     {
231         if( (*it).pWnd == pWnd )
232         {
233             msg_Dbg( getIntf(), "vout released vout=%p, VideoCtrl=%p",
234                              pWnd, (*it).pCtrlVideo );
235
236             // if a video control was being used, detach from it
237             if( (*it).pCtrlVideo )
238             {
239                 (*it).pCtrlVideo->detachVoutWindow( );
240             }
241
242             // remove resources
243             delete (*it).pVoutWindow;
244             m_SavedWndVec.erase( it );
245             break;
246         }
247     }
248 }
249
250
251 void VoutManager::setSizeWnd( vout_window_t *pWnd, int width, int height )
252 {
253    msg_Dbg( pWnd, "setSize (%dx%d) received from vout threadr",
254                   width, height );
255
256    vector<SavedWnd>::iterator it;
257    for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); it++ )
258    {
259        if( (*it).pWnd == pWnd )
260        {
261            VoutWindow* pVoutWindow = (*it).pVoutWindow;
262
263            pVoutWindow->setOriginalWidth( width );
264            pVoutWindow->setOriginalHeight( height );
265
266            CtrlVideo* pCtrlVideo = pVoutWindow->getCtrlVideo();
267            if( pCtrlVideo )
268            {
269                pCtrlVideo->resizeControl( width, height );
270            }
271            break;
272        }
273    }
274 }
275
276 void VoutManager::setFullscreenWnd( vout_window_t *pWnd, bool b_fullscreen )
277 {
278     msg_Dbg( pWnd, "setFullscreen (%d) received from vout thread",
279                     b_fullscreen ? 1 : 0 );
280
281     VlcProc::instance( getIntf() )->setFullscreenVar( b_fullscreen );
282
283     if( b_fullscreen )
284     {
285         m_pVoutMainWindow->show();
286     }
287     else
288     {
289         m_pVoutMainWindow->hide();
290     }
291 }
292
293 // Functions called by window provider
294 // ///////////////////////////////////
295
296 void *VoutManager::getWindow( intf_thread_t *pIntf, vout_window_t *pWnd )
297 {
298     // Theme may have been destroyed
299     if( !pIntf->p_sys->p_theme )
300         return NULL;
301
302     vlc_mutex_lock( &pIntf->p_sys->vout_lock );
303     pIntf->p_sys->b_vout_ready = false;
304     pIntf->p_sys->handle = NULL;
305
306     CmdNewVoutWindow *pCmd =
307         new CmdNewVoutWindow( pIntf, pWnd );
308
309     AsyncQueue *pQueue = AsyncQueue::instance( pIntf );
310     pQueue->push( CmdGenericPtr( pCmd ), false );
311
312     while( !pIntf->p_sys->b_vout_ready )
313         vlc_cond_wait( &pIntf->p_sys->vout_wait, &pIntf->p_sys->vout_lock );
314
315     void* handle = pIntf->p_sys->handle;
316     vlc_mutex_unlock( &pIntf->p_sys->vout_lock );
317
318     return handle;
319 }
320
321
322 void VoutManager::releaseWindow( intf_thread_t *pIntf, vout_window_t *pWnd )
323 {
324     vlc_mutex_lock( &pIntf->p_sys->vout_lock );
325     pIntf->p_sys->b_vout_ready = false;
326
327     CmdReleaseVoutWindow *pCmd =
328         new CmdReleaseVoutWindow( pIntf, pWnd );
329
330     AsyncQueue *pQueue = AsyncQueue::instance( pIntf );
331     pQueue->push( CmdGenericPtr( pCmd ), false );
332
333     while( !pIntf->p_sys->b_vout_ready )
334         vlc_cond_wait( &pIntf->p_sys->vout_wait, &pIntf->p_sys->vout_lock );
335
336     vlc_mutex_unlock( &pIntf->p_sys->vout_lock );
337 }
338
339
340 int VoutManager::controlWindow( struct vout_window_t *pWnd,
341                             int query, va_list args )
342 {
343     intf_thread_t *pIntf = (intf_thread_t *)pWnd->sys;
344     VoutManager *pThis = pIntf->p_sys->p_voutManager;
345
346     switch( query )
347     {
348         case VOUT_WINDOW_SET_SIZE:
349         {
350             unsigned int i_width  = va_arg( args, unsigned int );
351             unsigned int i_height = va_arg( args, unsigned int );
352
353             if( i_width && i_height )
354             {
355                 // Post a vout resize command
356                 CmdResizeVout *pCmd =
357                     new CmdResizeVout( pThis->getIntf(),
358                                         pWnd, (int)i_width, (int)i_height );
359                 AsyncQueue *pQueue =
360                    AsyncQueue::instance( pThis->getIntf() );
361                 pQueue->push( CmdGenericPtr( pCmd ) );
362             }
363             return VLC_EGENERIC;
364         }
365
366         case VOUT_WINDOW_SET_FULLSCREEN:
367         {
368             bool b_fullscreen = va_arg( args, int );
369
370             // Post a vout resize command
371             CmdSetFullscreen* pCmd =
372                 new CmdSetFullscreen( pThis->getIntf(), pWnd, b_fullscreen );
373
374             AsyncQueue *pQueue = AsyncQueue::instance( pThis->getIntf() );
375             pQueue->push( CmdGenericPtr( pCmd ) );
376
377             return VLC_SUCCESS;
378         }
379
380         case VOUT_WINDOW_SET_STATE:
381         {
382             unsigned i_arg = va_arg( args, unsigned );
383             unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
384
385             // Post a SetOnTop command
386             CmdSetOnTop* pCmd =
387                 new CmdSetOnTop( pThis->getIntf(), on_top );
388
389             AsyncQueue *pQueue = AsyncQueue::instance( pThis->getIntf() );
390             pQueue->push( CmdGenericPtr( pCmd ) );
391
392             return VLC_SUCCESS;
393         }
394
395
396         default:
397             msg_Dbg( pWnd, "control query not supported" );
398             return VLC_EGENERIC;
399     }
400 }
401