From: Erwan Tulou Date: Sat, 14 Mar 2009 23:10:49 +0000 (+0100) Subject: skins2 vout manager X-Git-Tag: 1.0.0-pre1~53 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=04af5c7c7d1d6a779f73c2384c8e40a32cbe35d9;p=vlc skins2 vout manager Signed-off-by: RĂ©mi Denis-Courmont --- diff --git a/modules/gui/skins2/Modules.am b/modules/gui/skins2/Modules.am index b975e1a13a..fc8a6c2bda 100644 --- a/modules/gui/skins2/Modules.am +++ b/modules/gui/skins2/Modules.am @@ -151,6 +151,8 @@ SOURCES_skins2 = \ src/vlcproc.hpp \ src/vout_window.cpp \ src/vout_window.hpp \ + src/vout_manager.cpp \ + src/vout_manager.hpp \ src/window_manager.cpp \ src/window_manager.hpp \ \ diff --git a/modules/gui/skins2/commands/cmd_change_skin.cpp b/modules/gui/skins2/commands/cmd_change_skin.cpp index ce31e23df6..27d28d58cb 100644 --- a/modules/gui/skins2/commands/cmd_change_skin.cpp +++ b/modules/gui/skins2/commands/cmd_change_skin.cpp @@ -29,6 +29,8 @@ #include "../src/theme.hpp" #include "../src/theme_loader.hpp" #include "../src/window_manager.hpp" +#include "../src/vout_manager.hpp" +#include "../src/vlcproc.hpp" void CmdChangeSkin::execute() @@ -42,6 +44,9 @@ void CmdChangeSkin::execute() pOldTheme->getWindowManager().hideAll(); } + VoutManager::instance( getIntf() )->lockVout(); + VoutManager::instance( getIntf() )->saveVoutConfig(); + ThemeLoader loader( getIntf() ); if( loader.load( m_file ) ) { @@ -49,16 +54,23 @@ void CmdChangeSkin::execute() msg_Info( getIntf(), "new theme successfully loaded (%s)", m_file.c_str() ); delete pOldTheme; + + // restore vout config + VoutManager::instance( getIntf() )->restoreVoutConfig( true ); + VoutManager::instance( getIntf() )->unlockVout(); } else if( pOldTheme ) { msg_Warn( getIntf(), "a problem occurred when loading the new theme," " restoring the previous one" ); getIntf()->p_sys->p_theme = pOldTheme; + VoutManager::instance( getIntf() )->restoreVoutConfig( false ); + VoutManager::instance( getIntf() )->unlockVout(); pOldTheme->getWindowManager().restoreVisibility(); } else { + VoutManager::instance( getIntf() )->unlockVout(); msg_Err( getIntf(), "cannot load the theme, aborting" ); // Quit CmdQuit cmd( getIntf() ); diff --git a/modules/gui/skins2/commands/cmd_resize.cpp b/modules/gui/skins2/commands/cmd_resize.cpp index ea3e4bc66f..5a768daf8b 100644 --- a/modules/gui/skins2/commands/cmd_resize.cpp +++ b/modules/gui/skins2/commands/cmd_resize.cpp @@ -26,6 +26,9 @@ #include "../src/generic_layout.hpp" #include "../src/window_manager.hpp" #include "../src/vlcproc.hpp" +#include "../src/vout_window.hpp" +#include "../controls/ctrl_video.hpp" +#include CmdResize::CmdResize( intf_thread_t *pIntf, const WindowManager &rWindowManager, @@ -57,3 +60,16 @@ void CmdResizeVout::execute() rVoutSize.setSize( m_width, m_height ); } + +CmdResizeInnerVout::CmdResizeInnerVout( intf_thread_t *pIntf, + CtrlVideo* pCtrlVideo ) + : CmdGeneric( pIntf ), m_pCtrlVideo( pCtrlVideo ) +{ +} + + +void CmdResizeInnerVout::execute() +{ + m_pCtrlVideo->resizeInnerVout(); +} + diff --git a/modules/gui/skins2/commands/cmd_resize.hpp b/modules/gui/skins2/commands/cmd_resize.hpp index c554c1800f..3233dd3eac 100644 --- a/modules/gui/skins2/commands/cmd_resize.hpp +++ b/modules/gui/skins2/commands/cmd_resize.hpp @@ -26,9 +26,12 @@ #define CMD_RESIZE_HPP #include "cmd_generic.hpp" +#include class WindowManager; class GenericLayout; +class CtrlVideo; +class VoutWindow; /// Command to resize a layout @@ -74,4 +77,22 @@ class CmdResizeVout: public CmdGeneric }; +/// Command to resize the inner vout window +class CmdResizeInnerVout: public CmdGeneric +{ + public: + /// Resize the given layout + CmdResizeInnerVout( intf_thread_t *pIntf, CtrlVideo* pCtrlVideo ); + virtual ~CmdResizeInnerVout() {} + + /// This method does the real job of the command + virtual void execute(); + + /// Return the type of the command + virtual string getType() const { return "resize inner vout"; } + + private: + CtrlVideo* m_pCtrlVideo; +}; + #endif diff --git a/modules/gui/skins2/controls/ctrl_generic.hpp b/modules/gui/skins2/controls/ctrl_generic.hpp index 7ab7ea4593..d0ed05da85 100644 --- a/modules/gui/skins2/controls/ctrl_generic.hpp +++ b/modules/gui/skins2/controls/ctrl_generic.hpp @@ -125,18 +125,21 @@ class CtrlGeneric: public SkinObject, public Observer /// Overload this method to get notified of bool variable changes virtual void onVarBoolUpdate( VarBool &rVar ) {} - private: + /// Method called when an observed bool variable is changed + virtual void onUpdate( Subject &rVariable , void* ); + /// Associated layout GenericLayout *m_pLayout; + + /// Visibility variable + VarBool *m_pVisible; + + private: /// Position in the layout Position *m_pPosition; /// Help text UString m_help; - /// Visibilty variable - VarBool *m_pVisible; - /// Method called when an observed bool variable is changed - virtual void onUpdate( Subject &rVariable , void* ); }; typedef CountedPtr CtrlGenericPtr; diff --git a/modules/gui/skins2/controls/ctrl_video.cpp b/modules/gui/skins2/controls/ctrl_video.cpp index 424a314c61..16c8e48ab7 100644 --- a/modules/gui/skins2/controls/ctrl_video.cpp +++ b/modules/gui/skins2/controls/ctrl_video.cpp @@ -26,6 +26,7 @@ #include "../src/vout_window.hpp" #include "../src/os_graphics.hpp" #include "../src/vlcproc.hpp" +#include "../src/vout_manager.hpp" #include "../src/window_manager.hpp" #include "../commands/async_queue.hpp" #include "../commands/cmd_resize.hpp" @@ -34,15 +35,20 @@ CtrlVideo::CtrlVideo( intf_thread_t *pIntf, GenericLayout &rLayout, bool autoResize, const UString &rHelp, VarBool *pVisible ): - CtrlGeneric( pIntf, rHelp, pVisible ), m_pVout( NULL ), - m_rLayout( rLayout ), m_xShift( 0 ), m_yShift( 0 ) + CtrlGeneric( pIntf, rHelp, pVisible ), m_rLayout( rLayout ), + m_xShift( 0 ), m_yShift( 0 ), m_bAutoResize( autoResize ), + m_pVoutWindow( NULL ), m_bIsUseable( false ) { // Observe the vout size variable if the control is auto-resizable - if( autoResize ) + if( m_bAutoResize ) { VarBox &rVoutSize = VlcProc::instance( pIntf )->getVoutSizeVar(); rVoutSize.addObserver( this ); } + + // observe visibility variable + if( m_pVisible ) + m_pVisible->addObserver( this ); } @@ -51,7 +57,10 @@ CtrlVideo::~CtrlVideo() VarBox &rVoutSize = VlcProc::instance( getIntf() )->getVoutSizeVar(); rVoutSize.delObserver( this ); - delete m_pVout; + //m_pLayout->getActiveVar().delObserver( this ); + + if( m_pVisible ) + m_pVisible->delObserver( this ); } @@ -69,10 +78,10 @@ bool CtrlVideo::mouseOver( int x, int y ) const void CtrlVideo::onResize() { const Position *pPos = getPosition(); - if( pPos && m_pVout ) + if( pPos && m_pVoutWindow ) { - m_pVout->move( pPos->getLeft(), pPos->getTop() ); - m_pVout->resize( pPos->getWidth(), pPos->getHeight() ); + m_pVoutWindow->move( pPos->getLeft(), pPos->getTop() ); + m_pVoutWindow->resize( pPos->getWidth(), pPos->getHeight() ); } } @@ -98,10 +107,26 @@ void CtrlVideo::draw( OSGraphics &rImage, int xDest, int yDest ) } -void CtrlVideo::onUpdate( Subject &rVoutSize, void *arg ) +void CtrlVideo::setLayout( GenericLayout *pLayout, + const Position &rPosition ) { - int newWidth = ((VarBox&)rVoutSize).getWidth() + m_xShift; - int newHeight = ((VarBox&)rVoutSize).getHeight() + m_yShift; + CtrlGeneric::setLayout( pLayout, rPosition ); + m_pLayout->getActiveVar().addObserver( this ); + + m_bIsUseable = isVisible() && m_pLayout->getActiveVar().get(); + + // register Video Control + VoutManager::instance( getIntf() )->registerCtrlVideo( this ); + + msg_Dbg( getIntf(),"New VideoControl detected(%x), useability=%s", + this, m_bIsUseable ? "true" : "false" ); +} + + +void CtrlVideo::resizeControl( int width, int height ) +{ + int newWidth = width + m_xShift; + int newHeight = height + m_yShift; // Create a resize command // FIXME: this way of getting the window manager kind of sucks @@ -112,32 +137,101 @@ void CtrlVideo::onUpdate( Subject &rVoutSize, void *arg ) m_rLayout, newWidth, newHeight ); // Push the command in the asynchronous command queue AsyncQueue *pQueue = AsyncQueue::instance( getIntf() ); - pQueue->push( CmdGenericPtr( pCmd ) ); + pQueue->push( CmdGenericPtr( pCmd ), false ); // FIXME: this should be a command too rWindowManager.stopResize(); + + pCmd = new CmdResizeInnerVout( getIntf(), this ); + pQueue->push( CmdGenericPtr( pCmd ), false ); + + TopWindow* pWin = getWindow(); + rWindowManager.show( *pWin ); } -void CtrlVideo::setVisible( bool visible ) +void CtrlVideo::onUpdate( Subject &rVoutSize, void *arg ) { - if( visible ) + int newWidth = ((VarBox&)rVoutSize).getWidth() + m_xShift; + int newHeight = ((VarBox&)rVoutSize).getHeight() + m_yShift; + + resizeControl( newWidth, newHeight ); +} + + +void CtrlVideo::onUpdate( Subject &rVariable, void *arg ) +{ + // Visibility changed + if( &rVariable == m_pVisible ) + { + msg_Dbg( getIntf(), "VideoCtrl : Visibility changed (visible=%d)", + isVisible() ); + } + + // Active Layout changed + if( &rVariable == &m_pLayout->getActiveVar() ) + { + msg_Dbg( getIntf(), "VideoCtrl : Active Layout changed (isActive=%d)", + m_pLayout->getActiveVar().get() ); + } + + m_bIsUseable = isVisible() && m_pLayout->getActiveVar().get(); + + if( m_bIsUseable && !isUsed() ) + { + VoutManager::instance( getIntf() )->requestVout( this ); + } + else if( !m_bIsUseable && isUsed() ) { - GenericWindow *pParent = getWindow(); - const Position *pPos = getPosition(); - // Create a child window for the vout if it doesn't exist yet - if( !m_pVout && pParent && pPos ) - { - m_pVout = new VoutWindow( getIntf(), pPos->getLeft(), - pPos->getTop(), false, false, *pParent ); - m_pVout->resize( pPos->getWidth(), pPos->getHeight() ); - m_pVout->show(); - } + VoutManager::instance( getIntf() )->discardVout( this ); } - else +} + +void CtrlVideo::attachVoutWindow( VoutWindow* pVoutWindow ) +{ + int width = pVoutWindow->getOriginalWidth(); + int height = pVoutWindow->getOriginalHeight(); + + WindowManager &rWindowManager = + getIntf()->p_sys->p_theme->getWindowManager(); + TopWindow* pWin = getWindow(); + rWindowManager.show( *pWin ); + + if( m_bAutoResize && width && height ) { - delete m_pVout; - m_pVout = NULL; + int newWidth = width + m_xShift; + int newHeight = height + m_yShift; + + rWindowManager.startResize( m_rLayout, WindowManager::kResizeSE ); + rWindowManager.resize( m_rLayout, newWidth, newHeight ); + rWindowManager.stopResize(); } + + pVoutWindow->setCtrlVideo( this ); + + m_pVoutWindow = pVoutWindow; +} + + +void CtrlVideo::detachVoutWindow( ) +{ + m_pVoutWindow->setCtrlVideo( NULL ); + m_pVoutWindow = NULL; +} + + +void CtrlVideo::resizeInnerVout( ) +{ + WindowManager &rWindowManager = + getIntf()->p_sys->p_theme->getWindowManager(); + TopWindow* pWin = getWindow(); + + const Position *pPos = getPosition(); + + m_pVoutWindow->resize( pPos->getWidth(), pPos->getHeight() ); + m_pVoutWindow->move( pPos->getLeft(), pPos->getTop() ); + + rWindowManager.show( *pWin ); + m_pVoutWindow->show(); } diff --git a/modules/gui/skins2/controls/ctrl_video.hpp b/modules/gui/skins2/controls/ctrl_video.hpp index 7869bd1e26..d7b67d5706 100644 --- a/modules/gui/skins2/controls/ctrl_video.hpp +++ b/modules/gui/skins2/controls/ctrl_video.hpp @@ -26,8 +26,9 @@ #include "ctrl_generic.hpp" #include "../utils/position.hpp" +#include "../src/vout_window.hpp" +#include -class VoutWindow; /// Control video class CtrlVideo: public CtrlGeneric, public Observer @@ -58,16 +59,52 @@ class CtrlVideo: public CtrlGeneric, public Observer /// Method called when the vout size is updated virtual void onUpdate( Subject &rVoutSize, void* ); - /// Called by the layout when the control is show/hidden - void setVisible( bool visible ); + /// Method called when visibility or ActiveLayout is updated + virtual void onUpdate( Subject &rVariable , void* ); + + // Attach a voutWindow to a Video Control + void attachVoutWindow( VoutWindow* pVoutWindow ); + + // Detach a voutWindow from a Video Control + void detachVoutWindow( ); + + // Update the inner part of the Video Control + void resizeInnerVout( ); + + // Get TopWindow associated with the video control + virtual TopWindow* getWindow() { return CtrlGeneric::getWindow(); } + + // Get the VoutWindow associated with the video control + virtual VoutWindow* getVoutWindow() { return m_pVoutWindow; } + + /// Set the position and the associated layout of the control + virtual void setLayout( GenericLayout *pLayout, + const Position &rPosition ); + + // resize the video Control + virtual void resizeControl( int width, int height ); + + // Is this control useable (visibility requirements) + virtual bool isUseable() { return m_bIsUseable; } + + // Is this control used + virtual bool isUsed() { return m_pVoutWindow ? true : false; } private: - /// Vout window - VoutWindow *m_pVout; /// Associated layout GenericLayout &m_rLayout; + + /// Autoresize parameter + bool m_bAutoResize; + /// Difference between layout size and video size int m_xShift, m_yShift; + + /// Is the video Control useable + bool m_bIsUseable; + + /// Vout window + VoutWindow *m_pVoutWindow; }; #endif diff --git a/modules/gui/skins2/src/generic_layout.cpp b/modules/gui/skins2/src/generic_layout.cpp index 3b8e65e566..dbc3cf67f5 100644 --- a/modules/gui/skins2/src/generic_layout.cpp +++ b/modules/gui/skins2/src/generic_layout.cpp @@ -31,6 +31,7 @@ #include "../controls/ctrl_generic.hpp" #include "../controls/ctrl_video.hpp" #include "../utils/var_bool.hpp" +#include GenericLayout::GenericLayout( intf_thread_t *pIntf, int width, int height, @@ -38,7 +39,7 @@ GenericLayout::GenericLayout( intf_thread_t *pIntf, int width, int height, int maxHeight ): SkinObject( pIntf ), m_pWindow( NULL ), m_rect( 0, 0, width, height ), m_minWidth( minWidth ), m_maxWidth( maxWidth ), - m_minHeight( minHeight ), m_maxHeight( maxHeight ), m_pVideoControl( NULL ), + m_minHeight( minHeight ), m_maxHeight( maxHeight ), m_pVideoCtrlSet(), m_visible( false ), m_pVarActive( NULL ) { // Get the OSFactory @@ -122,7 +123,7 @@ void GenericLayout::addControl( CtrlGeneric *pControl, // Check if it is a video control if( pControl->getType() == "video" ) { - m_pVideoControl = (CtrlVideo*)pControl; + m_pVideoCtrlSet.insert( (CtrlVideo*)pControl ); } } else @@ -233,38 +234,126 @@ void GenericLayout::refreshRect( int x, int y, int width, int height ) height = m_rect.getHeight() - y; // Refresh the window... but do not paint on a visible video control! - if( !m_pVideoControl || !m_pVideoControl->isVisible() ) + if( !m_pVideoCtrlSet.size() ) { // No video control, we can safely repaint the rectangle pWindow->refresh( x, y, width, height ); } else { - // Bad luck, there is a video control somewhere (not necessarily - // in the repainting zone, btw). - // We will divide the repainting into 4 regions (top, left, bottom - // and right). The overlapping parts (i.e. the corners) of these - // regions will be painted twice, because otherwise the algorithm - // becomes a real mess :) - - // Use short variable names for convenience - int xx = m_pVideoControl->getPosition()->getLeft(); - int yy = m_pVideoControl->getPosition()->getTop(); - int ww = m_pVideoControl->getPosition()->getWidth(); - int hh = m_pVideoControl->getPosition()->getHeight(); - - // Top part: - if( y < yy ) - pWindow->refresh( x, y, width, yy - y ); - // Left part: - if( x < xx ) - pWindow->refresh( x, y, xx - x, height ); - // Bottom part - if( y + height > yy + hh ) - pWindow->refresh( x, yy + hh, width, y + height - (yy + hh) ); - // Right part - if( x + width > xx + ww ) - pWindow->refresh( xx + ww, y, x + width - (xx + ww), height ); + // video control(s) present, we need more calculations + computeRefresh( x, y, width, height ); + } + } +} + +class rect +{ +public: + rect( int v_x = 0, int v_y = 0, + int v_width = 0, int v_height = 0 ) + : x( v_x), y( v_y ), width( v_width), height( v_height) + {} + ~rect(){} + int x; + int y; + int width; + int height; + + static bool isIncluded( rect& rect2, rect& rect1 ) + { + int x1 = rect1.x; + int y1 = rect1.y; + int w1 = rect1.width; + int h1 = rect1.height; + + int x2 = rect2.x; + int y2 = rect2.y; + int w2 = rect2.width; + int h2 = rect2.height; + + return x2 >= x1 && x2 < x1 + w1 + && y2 >= y1 && y2 < y1 + h1 + && w2 <= w1 + && h2 <= h1; + } +}; + +void GenericLayout::computeRefresh( int x, int y, int width, int height ) +{ + int w = width; + int h = height; + TopWindow *pWindow = getWindow(); + + set x_set; + set y_set; + vector rect_set; + + x_set.insert( x + w ); + y_set.insert( y + h ); + + // retrieve video controls being used + // and remember their rectangles + set::const_iterator it; + for( it = m_pVideoCtrlSet.begin(); it != m_pVideoCtrlSet.end(); it++ ) + { + if( (*it)->isUsed() ) + { + int xx = (*it)->getPosition()->getLeft(); + int yy = (*it)->getPosition()->getTop(); + int ww = (*it)->getPosition()->getWidth(); + int hh = (*it)->getPosition()->getHeight(); + + rect r(xx, yy, ww, hh ); + rect_set.push_back( r ); + + if( xx > x && xx < x + w ) + x_set.insert( xx ); + if( xx + ww > x && xx + ww < x + w ) + x_set.insert( xx + ww ); + if( yy > y && yy < y + h ) + y_set.insert( yy ); + if( yy + hh > y && yy + hh < y + h ) + y_set.insert( yy + hh ); + } + } + + // for each subregion, test whether they are part + // of the video control(s) or not + set::const_iterator it_x; + set::const_iterator it_y; + int x_prev, y_prev; + + for( x_prev = x, it_x = x_set.begin(); + it_x != x_set.end(); x_prev = *it_x, it_x++ ) + { + int x0 = x_prev; + int w0 = *it_x - x_prev; + + for( y_prev = y, it_y = y_set.begin(); + it_y != y_set.end(); y_prev = *it_y, it_y++ ) + { + int y0 = y_prev; + int h0 = *it_y - y_prev; + + rect r( x0, y0, w0, h0 ); + bool b_refresh = true; + + vector::iterator it; + for( it = rect_set.begin(); it != rect_set.end(); it++ ) + { + rect r_ctrl = *it; + if( rect::isIncluded( r, r_ctrl ) ) + { + b_refresh = false; + break; + } + } + + // subregion is not part of a video control + // needs to be refreshed + if( b_refresh ) + pWindow->refresh( x0, y0, w0 ,h0 ); } } } @@ -287,22 +376,11 @@ void GenericLayout::onShow() m_visible = true; refreshAll(); - // TODO find a better way to handle the vout ? - if( m_pVideoControl ) - { - m_pVideoControl->setVisible( true ); - } } void GenericLayout::onHide() { m_visible = false; - - // TODO find a better way to handle the vout ? - if( m_pVideoControl ) - { - m_pVideoControl->setVisible( false ); - } } diff --git a/modules/gui/skins2/src/generic_layout.hpp b/modules/gui/skins2/src/generic_layout.hpp index 7574f1fc08..9e6871af22 100644 --- a/modules/gui/skins2/src/generic_layout.hpp +++ b/modules/gui/skins2/src/generic_layout.hpp @@ -105,6 +105,9 @@ class GenericLayout: public SkinObject virtual int getMinHeight() const { return m_minHeight; } virtual int getMaxHeight() const { return m_maxHeight; } + /// specific refresh window (if video controls) + virtual void computeRefresh( int x, int y, int width, int height ); + /// Resize the layout virtual void resize( int width, int height ); @@ -156,8 +159,8 @@ class GenericLayout: public SkinObject OSGraphics *m_pImage; /// List of the controls in the layout list m_controlList; - /// Video control - CtrlVideo *m_pVideoControl; + /// Video control(s) + set m_pVideoCtrlSet; /// List of the anchors in the layout list m_anchorList; /// Flag to know if the layout is visible diff --git a/modules/gui/skins2/src/generic_window.cpp b/modules/gui/skins2/src/generic_window.cpp index e96f8328cb..cbad909af4 100644 --- a/modules/gui/skins2/src/generic_window.cpp +++ b/modules/gui/skins2/src/generic_window.cpp @@ -98,6 +98,10 @@ void GenericWindow::move( int left, int top ) void GenericWindow::resize( int width, int height ) { + // don't try when value is 0 (may crash) + if( !width || ! height ) + return; + // Update the window size m_width = width; m_height = height; @@ -157,3 +161,15 @@ void GenericWindow::innerHide() } } + +void* GenericWindow::getOSHandle() const +{ + return m_pOsWindow->getOSHandle(); +} + + +void GenericWindow::setParent( GenericWindow* pParent, int x, int y, int w, int h ) +{ + void* handle = pParent ? pParent->getOSHandle() : NULL; + m_pOsWindow->reparent( handle, x, y, w, h ); +} diff --git a/modules/gui/skins2/src/generic_window.hpp b/modules/gui/skins2/src/generic_window.hpp index f3c5bfece0..e75b733b7f 100644 --- a/modules/gui/skins2/src/generic_window.hpp +++ b/modules/gui/skins2/src/generic_window.hpp @@ -46,6 +46,8 @@ class GenericWindow: public SkinObject, public Observer { private: friend class WindowManager; + friend class VoutManager; + friend class CtrlVideo; public: GenericWindow( intf_thread_t *pIntf, int xPos, int yPos, bool dragDrop, bool playOnDrop, @@ -81,6 +83,12 @@ class GenericWindow: public SkinObject, public Observer /// Window type, mainly useful when overloaded (for VoutWindow) virtual string getType() const { return "Generic"; } + /// windows handle + void* getOSHandle() const; + + /// reparent + void setParent( GenericWindow* pParent, int x, int y, int w, int h ); + protected: /// Get the OS window OSWindow *getOSWindow() const { return m_pOsWindow; } diff --git a/modules/gui/skins2/src/os_window.hpp b/modules/gui/skins2/src/os_window.hpp index 439f206498..f756afb300 100644 --- a/modules/gui/skins2/src/os_window.hpp +++ b/modules/gui/skins2/src/os_window.hpp @@ -56,6 +56,12 @@ class OSWindow: public SkinObject /// Toggle the window on top virtual void toggleOnTop( bool onTop ) const = 0; + /// getter for handler + virtual void* getOSHandle( ) const = 0; + + /// reparent the window + virtual void reparent( void* OSHandle, int x, int y, int w, int h ) = 0; + protected: OSWindow( intf_thread_t *pIntf ): SkinObject( pIntf ) {} }; diff --git a/modules/gui/skins2/src/skin_common.hpp b/modules/gui/skins2/src/skin_common.hpp index ff169f9868..684deaf532 100644 --- a/modules/gui/skins2/src/skin_common.hpp +++ b/modules/gui/skins2/src/skin_common.hpp @@ -44,6 +44,7 @@ class OSFactory; class OSLoop; class VarManager; class VlcProc; +class VoutManager; class Theme; class ThemeRepository; @@ -132,6 +133,8 @@ struct intf_sys_t VarManager *p_varManager; /// VLC state handler VlcProc *p_vlcProc; + /// Vout manager + VoutManager *p_voutManager; /// Theme repository ThemeRepository *p_repository; diff --git a/modules/gui/skins2/src/skin_main.cpp b/modules/gui/skins2/src/skin_main.cpp index 9590e77760..af25cb4b54 100644 --- a/modules/gui/skins2/src/skin_main.cpp +++ b/modules/gui/skins2/src/skin_main.cpp @@ -42,6 +42,8 @@ #include "theme_loader.hpp" #include "theme.hpp" #include "theme_repository.hpp" +#include "vout_window.hpp" +#include "vout_manager.hpp" #include "../parser/interpreter.hpp" #include "../commands/async_queue.hpp" #include "../commands/cmd_quit.hpp" @@ -115,6 +117,7 @@ static int Open( vlc_object_t *p_this ) p_intf->p_sys->p_osFactory = NULL; p_intf->p_sys->p_osLoop = NULL; p_intf->p_sys->p_varManager = NULL; + p_intf->p_sys->p_voutManager = NULL; p_intf->p_sys->p_vlcProc = NULL; p_intf->p_sys->p_repository = NULL; @@ -170,6 +173,12 @@ static int Open( vlc_object_t *p_this ) #endif return VLC_EGENERIC; } + if( VoutManager::instance( p_intf ) == NULL ) + { + msg_Err( p_intf, "cannot instanciate VoutManager" ); + vlc_object_release( p_intf->p_sys->p_playlist ); + return VLC_EGENERIC; + } vlc_mutex_lock( &skin_load.mutex ); skin_load.intf = p_intf; vlc_mutex_unlock( &skin_load.mutex ); @@ -237,13 +246,23 @@ static void Close( vlc_object_t *p_this ) { intf_thread_t *p_intf = (intf_thread_t *)p_this; + msg_Dbg( p_intf, "closing skins2 module" ); + vlc_mutex_lock( &skin_load.mutex ); skin_load.intf = NULL; vlc_mutex_unlock( &skin_load.mutex); + if( p_intf->p_sys->p_theme ) + { + delete p_intf->p_sys->p_theme; + p_intf->p_sys->p_theme = NULL; + msg_Dbg( p_intf, "current theme deleted" ); + } + // Destroy "singleton" objects OSFactory::instance( p_intf )->destroyOSLoop(); ThemeRepository::destroy( p_intf ); + VoutManager::destroy( p_intf ); //Dialogs::destroy( p_intf ); Interpreter::destroy( p_intf ); AsyncQueue::destroy( p_intf ); @@ -283,8 +302,6 @@ static void Run( intf_thread_t *p_intf ) if( p_intf->p_sys->p_theme ) { p_intf->p_sys->p_theme->saveConfig(); - delete p_intf->p_sys->p_theme; - p_intf->p_sys->p_theme = NULL; } // cannot be called in "Close", because it refcounts skins2 @@ -304,15 +321,14 @@ static int WindowOpen( vlc_object_t *p_this ) if( pIntf == NULL ) return VLC_EGENERIC; - /* FIXME: most probably not thread-safe, - * albeit no worse than ever before */ - pWnd->handle.hwnd = VlcProc::getWindow( pIntf, pWnd->vout, - &pWnd->pos_x, &pWnd->pos_y, - &pWnd->width, &pWnd->height ); + vlc_object_release( pIntf ); + + pWnd->handle.hwnd = VoutManager::getWindow( pIntf, pWnd ); + if( pWnd->handle.hwnd ) { pWnd->p_private = pIntf; - pWnd->control = &VlcProc::controlWindow; + pWnd->control = &VoutManager::controlWindow; return VLC_SUCCESS; } else @@ -326,7 +342,7 @@ static void WindowClose( vlc_object_t *p_this ) vout_window_t *pWnd = (vout_window_t *)p_this; intf_thread_t *pIntf = (intf_thread_t *)p_this->p_private; - VlcProc::releaseWindow( pIntf, pWnd->handle.hwnd ); + VoutManager::releaseWindow( pIntf, pWnd ); } //--------------------------------------------------------------------------- diff --git a/modules/gui/skins2/src/theme_loader.cpp b/modules/gui/skins2/src/theme_loader.cpp index 3f9f9bcace..3f0d106271 100644 --- a/modules/gui/skins2/src/theme_loader.cpp +++ b/modules/gui/skins2/src/theme_loader.cpp @@ -116,9 +116,6 @@ bool ThemeLoader::load( const string &fileName ) } free( skin_last ); - // The new theme cannot embed a video output yet - VlcProc::instance( getIntf() )->dropVout(); - return true; } diff --git a/modules/gui/skins2/src/vlcproc.cpp b/modules/gui/skins2/src/vlcproc.cpp index 2d8abeaa7c..4c890150e2 100644 --- a/modules/gui/skins2/src/vlcproc.cpp +++ b/modules/gui/skins2/src/vlcproc.cpp @@ -177,6 +177,7 @@ VlcProc::~VlcProc() if( getIntf()->p_sys->p_input ) { vlc_object_release( getIntf()->p_sys->p_input ); + getIntf()->p_sys->p_input = NULL; } interaction_Unregister( getIntf() ); @@ -196,27 +197,6 @@ VlcProc::~VlcProc() var_DelCallback( getIntf(), "skin-to-load", onSkinToLoad, this ); } -#include - -void VlcProc::registerVoutWindow( void *pVoutWindow ) -{ - m_handleSet.insert( pVoutWindow ); - assert( !m_pVout ); -} - - -void VlcProc::unregisterVoutWindow( void *pVoutWindow ) -{ - m_handleSet.erase( pVoutWindow ); -} - - -void VlcProc::dropVout() -{ - assert( !m_pVout ); -} - - void VlcProc::manage() { // Did the user request to quit vlc ? @@ -556,73 +536,6 @@ void VlcProc::updateStreamName() pQueue->push( CmdGenericPtr( pCmdItem ) ); } -void *VlcProc::getWindow( intf_thread_t *pIntf, vout_thread_t *pVout, - int *pXHint, int *pYHint, - unsigned int *pWidthHint, - unsigned int *pHeightHint ) -{ - VlcProc *pThis = pIntf->p_sys->p_vlcProc; - if( pThis->m_handleSet.empty() ) - { - return NULL; - } - else - { - pThis->m_pVout = pVout; - // Get the window handle - void *pWindow = *pThis->m_handleSet.begin(); - // Post a resize vout command - CmdResizeVout *pCmd = new CmdResizeVout( pThis->getIntf(), pWindow, - *pWidthHint, *pHeightHint ); - AsyncQueue *pQueue = AsyncQueue::instance( pThis->getIntf() ); - pQueue->push( CmdGenericPtr( pCmd ) ); - return pWindow; - } -} - - -void VlcProc::releaseWindow( intf_thread_t *pIntf, void *pWindow ) -{ - VlcProc *pThis = pIntf->p_sys->p_vlcProc; - pThis->m_pVout = NULL; -} - - -int VlcProc::controlWindow( struct vout_window_t *pWnd, - int query, va_list args ) -{ - intf_thread_t *pIntf = (intf_thread_t *)pWnd->p_private; - VlcProc *pThis = pIntf->p_sys->p_vlcProc; - - switch( query ) - { - case VOUT_SET_SIZE: - { - if( pThis->m_pVout ) - { - unsigned int i_width = va_arg( args, unsigned int ); - unsigned int i_height = va_arg( args, unsigned int ); - if( !i_width ) i_width = pThis->m_pVout->i_window_width; - if( !i_height ) i_height = pThis->m_pVout->i_window_height; - - // Post a resize vout command - CmdResizeVout *pCmd = - new CmdResizeVout( pThis->getIntf(), pWnd->handle.hwnd, - i_width, i_height ); - AsyncQueue *pQueue = AsyncQueue::instance( pThis->getIntf() ); - pQueue->push( CmdGenericPtr( pCmd ) ); - } - } - - default: - msg_Dbg( pWnd, "control query not supported" ); - break; - } - - return VLC_SUCCESS; -} - - int VlcProc::onEqBandsChange( vlc_object_t *pObj, const char *pVariable, vlc_value_t oldVal, vlc_value_t newVal, void *pParam ) diff --git a/modules/gui/skins2/src/vlcproc.hpp b/modules/gui/skins2/src/vlcproc.hpp index c69b2e6e22..42e0d95211 100644 --- a/modules/gui/skins2/src/vlcproc.hpp +++ b/modules/gui/skins2/src/vlcproc.hpp @@ -27,6 +27,7 @@ #include +#include #include "../vars/equalizer.hpp" #include "../vars/playtree.hpp" #include "../vars/time.hpp" @@ -34,6 +35,7 @@ #include "../utils/position.hpp" #include "../utils/var_text.hpp" #include "../commands/cmd_generic.hpp" +#include "../controls/ctrl_video.hpp" class OSTimer; class VarBool; @@ -80,19 +82,9 @@ class VlcProc: public SkinObject /// Getter for the vout size variable VarBox &getVoutSizeVar() { return m_varVoutSize; } - /// Set the vout window handle - void registerVoutWindow( void *pVoutWindow ); - - /// Unset the vout window handle - void unregisterVoutWindow( void *pVoutWindow ); - /// Indicate whether the embedded video output is currently used bool isVoutUsed() const { return m_pVout != NULL; } - /// If an embedded video output is used, drop it (i.e. tell it to stop - /// using our window handle) - void dropVout(); - protected: // Protected because it is a singleton VlcProc( intf_thread_t *pIntf ); @@ -135,12 +127,6 @@ class VlcProc: public SkinObject /// Variable for DVD detection VariablePtr m_cVarDvdActive; - /// Set of handles of vout windows - /** - * When changing the skin, the handles of the 2 skins coexist in the - * set (but this is temporary, until the old theme is destroyed). - */ - set m_handleSet; /// Vout thread vout_thread_t *m_pVout; /// Audio output @@ -209,21 +195,6 @@ class VlcProc: public SkinObject vlc_value_t oldVal, vlc_value_t newVal, void *pParam ); - public: /* FIXME: these used to be private for a reason */ - /// Callback to request a vout window - static void *getWindow( intf_thread_t *pIntf, vout_thread_t *pVout, - int *pXHint, int *pYHint, - unsigned int *pWidthHint, - unsigned int *pHeightHint ); - - /// Callback to release a vout window - static void releaseWindow( intf_thread_t *pIntf, void *pWindow ); - - /// Callback to change a vout window - static int controlWindow( struct vout_window_t *pWnd, - int query, va_list args ); - private: /* end of FIXME */ - /// Callback for equalizer-bands variable static int onEqBandsChange( vlc_object_t *pObj, const char *pVariable, vlc_value_t oldVal, vlc_value_t newVal, diff --git a/modules/gui/skins2/src/vout_manager.cpp b/modules/gui/skins2/src/vout_manager.cpp new file mode 100644 index 0000000000..fd0242d570 --- /dev/null +++ b/modules/gui/skins2/src/vout_manager.cpp @@ -0,0 +1,303 @@ +/***************************************************************************** + * vout_manager.cpp + ***************************************************************************** + * Copyright (C) 2009 the VideoLAN team + * $Id$ + * + * Authors: Erwan Tulou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "vout_manager.hpp" +#include "window_manager.hpp" +#include "vlcproc.hpp" +#include "../commands/async_queue.hpp" +#include "../commands/cmd_show_window.hpp" +#include "../commands/cmd_resize.hpp" + + + +VoutManager *VoutManager::instance( intf_thread_t *pIntf ) +{ + if( pIntf->p_sys->p_voutManager == NULL ) + { + pIntf->p_sys->p_voutManager = new VoutManager( pIntf ); + } + + return pIntf->p_sys->p_voutManager; +} + + +void VoutManager::destroy( intf_thread_t *pIntf ) +{ + if( pIntf->p_sys->p_voutManager ) + { + delete pIntf->p_sys->p_voutManager; + pIntf->p_sys->p_voutManager = NULL; + } +} + + +VoutManager::VoutManager( intf_thread_t *pIntf ): SkinObject( pIntf ), + m_pVoutMainWindow( NULL ), m_pCtrlVideoVec(), + m_pCtrlVideoVecBackup(), m_SavedVoutVec() +{ + vlc_mutex_init( &vout_lock ); + + m_pVoutMainWindow = new VoutMainWindow( getIntf() ); +} + + +VoutManager::~VoutManager( ) +{ + vlc_mutex_destroy( &vout_lock ); + + delete m_pVoutMainWindow; +} + + +void VoutManager::registerCtrlVideo( CtrlVideo* p_CtrlVideo ) +{ + m_pCtrlVideoVec.push_back( p_CtrlVideo ); +} + + +void VoutManager::saveVoutConfig( ) +{ + // Save width/height to be consistent across themes + // and detach Video Controls + vector::iterator it; + for( it = m_SavedVoutVec.begin(); it != m_SavedVoutVec.end(); it++ ) + { + if( (*it).pCtrlVideo ) + { + // detach vout thread from VideoControl + (*it).pCtrlVideo->detachVoutWindow( ); + + // memorize width/height before VideoControl is destroyed + (*it).width = (*it).pCtrlVideo->getPosition()->getWidth(); + (*it).height = (*it).pCtrlVideo->getPosition()->getHeight(); + (*it).pCtrlVideo = NULL; + } + } + + // Create a backup copy and reset original for new theme + m_pCtrlVideoVecBackup = m_pCtrlVideoVec; + m_pCtrlVideoVec.clear(); +} + + +void VoutManager::restoreVoutConfig( bool b_success ) +{ + if( !b_success ) + { + // loading new theme failed, restoring previous theme + m_pCtrlVideoVec = m_pCtrlVideoVecBackup; + } + + // reattach vout(s) to Video Controls + vector::iterator it; + for( it = m_SavedVoutVec.begin(); it != m_SavedVoutVec.end(); it++ ) + { + CtrlVideo* pCtrlVideo = getBestCtrlVideo(); + if( pCtrlVideo ) + { + pCtrlVideo->attachVoutWindow( (*it).pVoutWindow ); + (*it).pCtrlVideo = pCtrlVideo; + } + } +} + + +void VoutManager::discardVout( CtrlVideo* pCtrlVideo ) +{ + vector::iterator it; + for( it = m_SavedVoutVec.begin(); it != m_SavedVoutVec.end(); it++ ) + { + if( (*it).pCtrlVideo == pCtrlVideo ) + { + // detach vout thread from VideoControl + (*it).pCtrlVideo->detachVoutWindow( ); + (*it).width = (*it).pCtrlVideo->getPosition()->getWidth(); + (*it).height = (*it).pCtrlVideo->getPosition()->getHeight(); + (*it).pCtrlVideo = NULL; + break; + } + } +} + + +void VoutManager::requestVout( CtrlVideo* pCtrlVideo ) +{ + vector::iterator it; + for( it = m_SavedVoutVec.begin(); it != m_SavedVoutVec.end(); it++ ) + { + if( (*it).pCtrlVideo == NULL ) + { + pCtrlVideo->attachVoutWindow( (*it).pVoutWindow ); + (*it).pCtrlVideo = pCtrlVideo; + break; + } + } +} + + +CtrlVideo* VoutManager::getBestCtrlVideo( ) +{ + // try to find an unused useable VideoControl + + vector::const_iterator it; + for( it = m_pCtrlVideoVec.begin(); it != m_pCtrlVideoVec.end(); it++ ) + { + if( (*it)->isUseable() && !(*it)->isUsed() ) + { + return (*it); + } + } + + return NULL; +} + + +void* VoutManager::acceptVout( vout_thread_t* pVout, int width, int height ) +{ + // Creation of a dedicated Window per vout thread + VoutWindow* pVoutWindow = new VoutWindow( getIntf(), pVout, width, height, + (GenericWindow*) m_pVoutMainWindow ); + + void* handle = pVoutWindow->getOSHandle(); + + // try to find a video Control within the theme + CtrlVideo* pCtrlVideo = getBestCtrlVideo(); + if( pCtrlVideo ) + { + // A Video Control is available + // directly attach vout thread to it + pCtrlVideo->attachVoutWindow( pVoutWindow ); + } + + // save vout characteristics + m_SavedVoutVec.push_back( SavedVout( pVout, pVoutWindow, pCtrlVideo ) ); + + msg_Dbg( getIntf(), "New incoming vout=0x%x, handle=0x%x, VideoCtrl=0x%x", + pVout, handle, pCtrlVideo ); + + return handle; +} + + +// Functions called by window provider +// /////////////////////////////////// + +void *VoutManager::getWindow( intf_thread_t *pIntf, vout_window_t *pWnd ) +{ + // Theme may have been destroyed + if( !pIntf->p_sys->p_theme ) + return NULL; + + VoutManager *pThis = pIntf->p_sys->p_voutManager; + + vout_thread_t* pVout = pWnd->vout; + int width = (int)pWnd->width; + int height = (int)pWnd->height; + + pThis->lockVout(); + + void* handle = pThis->acceptVout( pVout, width, height ); + + pThis->unlockVout(); + + return handle; +} + + +void VoutManager::releaseWindow( intf_thread_t *pIntf, vout_window_t *pWnd ) +{ + VoutManager *pThis = pIntf->p_sys->p_voutManager; + + // Theme may have been destroyed + if( !pIntf->p_sys->p_theme ) + return; + + vout_thread_t* pVout = pWnd->vout; + + pThis->lockVout(); + + // remove vout thread from savedVec + vector::iterator it; + for( it = pThis->m_SavedVoutVec.begin(); it != pThis->m_SavedVoutVec.end(); it++ ) + { + if( (*it).pVout == pVout ) + { + msg_Dbg( pIntf, "vout released vout=0x%x, VideoCtrl=0x%x", + pVout, (*it).pCtrlVideo ); + + // if a video control was being used, detach from it + if( (*it).pCtrlVideo ) + { + (*it).pCtrlVideo->detachVoutWindow( ); + } + + // remove resources + delete (*it).pVoutWindow; + pThis->m_SavedVoutVec.erase( it ); + break; + } + } + + pThis->unlockVout(); +} + + +int VoutManager::controlWindow( struct vout_window_t *pWnd, + int query, va_list args ) +{ + intf_thread_t *pIntf = (intf_thread_t *)pWnd->p_private; + VoutManager *pThis = pIntf->p_sys->p_voutManager; + + switch( query ) + { + case VOUT_SET_SIZE: + { + unsigned int i_width = va_arg( args, unsigned int ); + unsigned int i_height = va_arg( args, unsigned int ); + + if( i_width && i_height ) + { + // Post a resize vout command + CmdResizeVout *pCmd = + new CmdResizeVout( pThis->getIntf(), pWnd->handle.hwnd, + i_width, i_height ); + AsyncQueue *pQueue = AsyncQueue::instance( pThis->getIntf() ); + pQueue->push( CmdGenericPtr( pCmd ) ); + } + } + + default: + msg_Dbg( pWnd, "control query not supported" ); + break; + } + + return VLC_SUCCESS; +} + diff --git a/modules/gui/skins2/src/vout_manager.hpp b/modules/gui/skins2/src/vout_manager.hpp new file mode 100644 index 0000000000..1d658e8519 --- /dev/null +++ b/modules/gui/skins2/src/vout_manager.hpp @@ -0,0 +1,137 @@ +/***************************************************************************** + * vout_manager.hpp + ***************************************************************************** + * Copyright (C) 2009 the VideoLAN team + * $Id$ + * + * Authors: Erwan Tulou < brezhoneg1 at yahoo.fr r> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifndef VOUTMANAGER_HPP +#define VOUTMANAGER_HPP + +#include + +#include +#include +#include "../utils/position.hpp" +#include "../commands/cmd_generic.hpp" +#include "../controls/ctrl_video.hpp" + +class VarBool; +class GenericWindow; + +#include + +class SavedVout +{ +public: + SavedVout( vout_thread_t* pVout, VoutWindow* pVoutWindow = NULL, + CtrlVideo* pCtrlVideo = NULL, int height = 0, int width = 0 ) : + pVout( pVout ), pVoutWindow( pVoutWindow ), pCtrlVideo( pCtrlVideo ), + height( height ), width( width ) {} + + ~SavedVout() {} + + vout_thread_t* pVout; + VoutWindow *pVoutWindow; + CtrlVideo *pCtrlVideo; + int height; + int width; +}; + +class VoutMainWindow: public GenericWindow +{ + public: + + VoutMainWindow( intf_thread_t *pIntf, int left = 0, int top = 0 ) : + GenericWindow( pIntf, left, top, false, false, NULL ) + { + resize( 10, 10 ); + move( -50, -50 ); + } + virtual ~VoutMainWindow() {} + +}; + + +/// Singleton object handling VLC internal state and playlist +class VoutManager: public SkinObject +{ + public: + /// Get the instance of VoutManager + /// Returns NULL if the initialization of the object failed + static VoutManager *instance( intf_thread_t *pIntf ); + + /// Delete the instance of VoutManager + static void destroy( intf_thread_t *pIntf ); + + /// Callback to request a vout window + static void *getWindow( intf_thread_t *pIntf, vout_window_t *pWnd ); + + /// Accept Vout + void* acceptVout( vout_thread_t* pVout, int width, int height ); + + // Window provider (release) + static void releaseWindow( intf_thread_t *pIntf, vout_window_t *pWnd ); + + /// Callback to change a vout window + static int controlWindow( struct vout_window_t *pWnd, + int query, va_list args ); + + // Register Video Controls (when building theme) + void registerCtrlVideo( CtrlVideo* p_CtrlVideo ); + + // save and restore vouts (when changing theme) + void saveVoutConfig( ); + void restoreVoutConfig( bool b_success ); + + // save and restore vouts (when swapping Layout) + void discardVout( CtrlVideo* pCtrlVideo ); + void requestVout( CtrlVideo* pCtrlVideo ); + + // get a VoutWindow + void* getHandle( vout_thread_t* pVout, int width, int height ); + + // get a useable video Control + CtrlVideo* getBestCtrlVideo( ); + + // get the VoutMainWindow + VoutMainWindow* getVoutMainWindow() { return m_pVoutMainWindow; } + + // (un)lock functions to protect vout sets + void lockVout( ) { vlc_mutex_lock( &vout_lock ); } + void unlockVout( ) { vlc_mutex_unlock( &vout_lock ); } + + protected: + // Protected because it is a singleton + VoutManager( intf_thread_t *pIntf ); + virtual ~VoutManager(); + + private: + + vector m_pCtrlVideoVec; + vector m_pCtrlVideoVecBackup; + vector m_SavedVoutVec; + + VoutMainWindow* m_pVoutMainWindow; + + vlc_mutex_t vout_lock; +}; + + +#endif diff --git a/modules/gui/skins2/src/vout_window.cpp b/modules/gui/skins2/src/vout_window.cpp index ea38033327..830e06ffed 100644 --- a/modules/gui/skins2/src/vout_window.cpp +++ b/modules/gui/skins2/src/vout_window.cpp @@ -22,38 +22,49 @@ *****************************************************************************/ #include "vout_window.hpp" +#include "vout_manager.hpp" #include "vlcproc.hpp" +#include "theme.hpp" #include "os_factory.hpp" #include "os_graphics.hpp" #include "os_window.hpp" +int VoutWindow::count = 0; -VoutWindow::VoutWindow( intf_thread_t *pIntf, int left, int top, - bool dragDrop, bool playOnDrop, - GenericWindow &rParent ): - GenericWindow( pIntf, left, top, dragDrop, playOnDrop, - &rParent ), m_pImage( NULL ) +VoutWindow::VoutWindow( intf_thread_t *pIntf, vout_thread_t* pVout, + int width, int height, GenericWindow* pParent ) : + GenericWindow( pIntf, 0, 0, false, false, pParent ), + m_pVout( pVout ), original_width( width ), original_height( height ), + m_pParentWindow( pParent ), m_pImage( NULL ) { + // counter for debug + count++; + + if( m_pVout ) + vlc_object_hold( m_pVout ); + + // needed on MS-Windows to prevent vlc hanging + show(); } VoutWindow::~VoutWindow() { delete m_pImage; + if( m_pVout ) + vlc_object_release( m_pVout ); - // Get the VlcProc - VlcProc *pVlcProc = getIntf()->p_sys->p_vlcProc; - - // Reparent the video output - if( pVlcProc && pVlcProc->isVoutUsed() ) - { - pVlcProc->dropVout(); - } + count--; + msg_Dbg( getIntf(), "VoutWindow count = %d", count ); } void VoutWindow::resize( int width, int height ) { + // don't try to resize with zero value + if( !width || !height ) + return; + // Get the OSFactory OSFactory *pOsFactory = OSFactory::instance( getIntf() ); @@ -72,11 +83,7 @@ void VoutWindow::refresh( int left, int top, int width, int height ) { if( m_pImage ) { - // Get the VlcProc - VlcProc *pVlcProc = getIntf()->p_sys->p_vlcProc; - - // Refresh only when there is no video! - if( pVlcProc && !pVlcProc->isVoutUsed() ) + if( !m_pCtrlVideo ) { m_pImage->copyToWindow( *getOSWindow(), left, top, width, height, left, top ); @@ -84,3 +91,27 @@ void VoutWindow::refresh( int left, int top, int width, int height ) } } +void VoutWindow::setCtrlVideo( CtrlVideo* pCtrlVideo ) +{ + if( pCtrlVideo ) + { + const Position *pPos = pCtrlVideo->getPosition(); + int x = pPos->getLeft(); + int y = pPos->getTop(); + int w = pPos->getWidth(); + int h = pPos->getHeight(); + + setParent( pCtrlVideo->getWindow(), x, y, w, h ); + m_pParentWindow = pCtrlVideo->getWindow(); + } + else + { + setParent( VoutManager::instance( getIntf() )->getVoutMainWindow(), + 0, 0, 0, 0 ); + m_pParentWindow = + VoutManager::instance( getIntf() )->getVoutMainWindow(); + } + + m_pCtrlVideo = pCtrlVideo; +} + diff --git a/modules/gui/skins2/src/vout_window.hpp b/modules/gui/skins2/src/vout_window.hpp index df03c2b7a7..90d8225214 100644 --- a/modules/gui/skins2/src/vout_window.hpp +++ b/modules/gui/skins2/src/vout_window.hpp @@ -27,34 +27,64 @@ #include "generic_window.hpp" class OSGraphics; +class CtrlVideo; /// Class to handle a video output window class VoutWindow: private GenericWindow { public: - VoutWindow( intf_thread_t *pIntf, int xPos, int yPos, - bool dragDrop, bool playOnDrop, GenericWindow &rParent ); + + VoutWindow( intf_thread_t *pIntf, vout_thread_t* pVout, + int width, int height, GenericWindow* pParent = NULL ); virtual ~VoutWindow(); + // counter used for debugging purpose + static int count; + /// Make some functions public //@{ using GenericWindow::show; using GenericWindow::hide; using GenericWindow::move; + using GenericWindow::getOSHandle; //@} /// Resize the window virtual void resize( int width, int height ); + /// get the parent window + virtual GenericWindow* getWindow( ) { return m_pParentWindow; } + /// Refresh an area of the window virtual void refresh( int left, int top, int width, int height ); + /// set Video Control for VoutWindow + virtual void setCtrlVideo( CtrlVideo* pCtrlVideo ); + + /// get original size of vout + virtual int getOriginalWidth( ) { return original_width; } + virtual int getOriginalHeight( ) { return original_height; } + virtual string getType() const { return "Vout"; } private: + /// Image when there is no video OSGraphics *m_pImage; + + /// vout thread + vout_thread_t* m_pVout; + + /// original width and height + int original_width; + int original_height; + + /// VideoControl attached to it + CtrlVideo* m_pCtrlVideo; + + /// Parent Window + GenericWindow* m_pParentWindow; }; typedef CountedPtr VoutWindowPtr; diff --git a/modules/gui/skins2/src/window_manager.cpp b/modules/gui/skins2/src/window_manager.cpp index b2ccf99913..01385b5682 100644 --- a/modules/gui/skins2/src/window_manager.cpp +++ b/modules/gui/skins2/src/window_manager.cpp @@ -639,3 +639,4 @@ void WindowManager::setActiveLayout( TopWindow &rWindow, // Rebuild the dependencies stopMove(); } + diff --git a/modules/gui/skins2/win32/win32_window.cpp b/modules/gui/skins2/win32/win32_window.cpp index 5758b37f75..2db62c20fd 100644 --- a/modules/gui/skins2/win32/win32_window.cpp +++ b/modules/gui/skins2/win32/win32_window.cpp @@ -54,18 +54,19 @@ Win32Window::Win32Window( intf_thread_t *pIntf, GenericWindow &rWindow, if( pParentWindow ) { // Child window (for vout) - HWND hParent = pParentWindow->getHandle(); + m_hWnd_parent = pParentWindow->getHandle(); m_hWnd = CreateWindowEx( WS_EX_TOOLWINDOW, "SkinWindowClass", "default name", WS_CHILD, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, hParent, 0, hInst, NULL ); + CW_USEDEFAULT, CW_USEDEFAULT, m_hWnd_parent, 0, hInst, NULL ); } else { // Normal window + m_hWnd_parent = hParentWindow; m_hWnd = CreateWindowEx( WS_EX_TOOLWINDOW, "SkinWindowClass", "default name", WS_POPUP | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, hParentWindow, 0, hInst, NULL ); + CW_USEDEFAULT, CW_USEDEFAULT, m_hWnd_parent, 0, hInst, NULL ); } if( !m_hWnd ) @@ -86,22 +87,11 @@ Win32Window::Win32Window( intf_thread_t *pIntf, GenericWindow &rWindow, // Register the window as a drop target RegisterDragDrop( m_hWnd, m_pDropTarget ); } - - // Set this window as a vout - if( m_pParent ) - { - VlcProc::instance( getIntf() )->registerVoutWindow( (void*)m_hWnd ); - } } Win32Window::~Win32Window() { - if( m_pParent ) - { - VlcProc::instance( getIntf() )->unregisterVoutWindow( (void*)m_hWnd ); - } - Win32Factory *pFactory = (Win32Factory*)Win32Factory::instance( getIntf() ); pFactory->m_windowMap[m_hWnd] = NULL; @@ -119,6 +109,14 @@ Win32Window::~Win32Window() } +void Win32Window::reparent( void* OSHandle, int x, int y, int w, int h ) +{ + // Reparent the window + SetParent( m_hWnd, (HWND)OSHandle ); + MoveWindow( m_hWnd, x, y, w, h, true ); +} + + void Win32Window::show( int left, int top ) const { ShowWindow( m_hWnd, SW_SHOW ); diff --git a/modules/gui/skins2/win32/win32_window.hpp b/modules/gui/skins2/win32/win32_window.hpp index 22e1cbe4e6..966a463202 100644 --- a/modules/gui/skins2/win32/win32_window.hpp +++ b/modules/gui/skins2/win32/win32_window.hpp @@ -62,9 +62,17 @@ class Win32Window: public OSWindow /// Getter for the window handle HWND getHandle() const { return m_hWnd; } + /// Getter for the window handle + void* getOSHandle() const { return (void*) m_hWnd; } + + /// reparent the window + void reparent( void* OSHandle, int x, int y, int w, int h ); + private: /// Window handle HWND m_hWnd; + /// Window parent's handle + HWND m_hWnd_parent; /// Indicates whether the window handles drag&drop events bool m_dragDrop; /// Drop target diff --git a/modules/gui/skins2/x11/x11_factory.cpp b/modules/gui/skins2/x11/x11_factory.cpp index 815a169a47..fe80a7b768 100644 --- a/modules/gui/skins2/x11/x11_factory.cpp +++ b/modules/gui/skins2/x11/x11_factory.cpp @@ -55,6 +55,10 @@ X11Factory::~X11Factory() bool X11Factory::init() { + // make sure xlib is safe-thread + if( !XInitThreads() ) + msg_Err( getIntf(), "initializing xlib for multi-threading failed" ); + // Create the X11 display m_pDisplay = new X11Display( getIntf() ); diff --git a/modules/gui/skins2/x11/x11_loop.cpp b/modules/gui/skins2/x11/x11_loop.cpp index cc52fa6997..f9cd7779d6 100644 --- a/modules/gui/skins2/x11/x11_loop.cpp +++ b/modules/gui/skins2/x11/x11_loop.cpp @@ -175,7 +175,6 @@ void X11Loop::handleX11Event() if( !pWin ) { - msg_Warn( getIntf(), "no associated generic window" ); return; } diff --git a/modules/gui/skins2/x11/x11_window.cpp b/modules/gui/skins2/x11/x11_window.cpp index 03ec09fe97..3c205922f6 100644 --- a/modules/gui/skins2/x11/x11_window.cpp +++ b/modules/gui/skins2/x11/x11_window.cpp @@ -41,20 +41,36 @@ X11Window::X11Window( intf_thread_t *pIntf, GenericWindow &rWindow, OSWindow( pIntf ), m_rDisplay( rDisplay ), m_pParent( pParentWindow ), m_dragDrop( dragDrop ) { - Window parent; if (pParentWindow) { - parent = pParentWindow->m_wnd; + m_wnd_parent = pParentWindow->m_wnd; } else { - parent = DefaultRootWindow( XDISPLAY ); + m_wnd_parent = DefaultRootWindow( XDISPLAY ); } XSetWindowAttributes attr; + attr.event_mask = ExposureMask | StructureNotifyMask; // Create the window - m_wnd = XCreateWindow( XDISPLAY, parent, 0, 0, 1, 1, 0, 0, - InputOutput, CopyFromParent, 0, &attr ); + m_wnd = XCreateWindow( XDISPLAY, m_wnd_parent, -10, 0, 1, 1, 0, 0, + InputOutput, CopyFromParent, CWEventMask, &attr ); + + // Make sure window is created before returning + XMapWindow( XDISPLAY, m_wnd ); + bool b_map_notify = false; + do + { + XEvent xevent; + XWindowEvent( XDISPLAY, m_wnd, SubstructureNotifyMask | + StructureNotifyMask, &xevent); + if( (xevent.type == MapNotify) + && (xevent.xmap.window == m_wnd ) ) + { + b_map_notify = true; + } + } while( ! b_map_notify ); + XUnmapWindow( XDISPLAY, m_wnd ); // Set the colormap for 8bpp mode if( XPIXELSIZE == 1 ) @@ -109,22 +125,11 @@ X11Window::X11Window( intf_thread_t *pIntf, GenericWindow &rWindow, // Associate the window to the main "parent" window XSetTransientForHint( XDISPLAY, m_wnd, m_rDisplay.getMainWindow() ); - // Set this window as a vout - if( m_pParent ) - { - VlcProc::instance( getIntf() )->registerVoutWindow( (void*)m_wnd ); - } - } X11Window::~X11Window() { - if( m_pParent ) - { - VlcProc::instance( getIntf() )->unregisterVoutWindow( (void*)m_wnd ); - } - X11Factory *pFactory = (X11Factory*)X11Factory::instance( getIntf() ); pFactory->m_windowMap[m_wnd] = NULL; pFactory->m_dndMap[m_wnd] = NULL; @@ -137,6 +142,19 @@ X11Window::~X11Window() XSync( XDISPLAY, False ); } +void X11Window::reparent( void* OSHandle, int x, int y, int w, int h ) +{ + // Reparent the window + Window new_parent = + OSHandle ? (Window) OSHandle : DefaultRootWindow( XDISPLAY ); + + if( w && h ) + XResizeWindow( XDISPLAY, m_wnd, w, h ); + + XReparentWindow( XDISPLAY, m_wnd, new_parent, x, y); + m_wnd_parent = new_parent; +} + void X11Window::show( int left, int top ) const { @@ -155,7 +173,10 @@ void X11Window::hide() const void X11Window::moveResize( int left, int top, int width, int height ) const { - XMoveResizeWindow( XDISPLAY, m_wnd, left, top, width, height ); + if( width && height ) + XMoveResizeWindow( XDISPLAY, m_wnd, left, top, width, height ); + else + XMoveWindow( XDISPLAY, m_wnd, left, top ); } diff --git a/modules/gui/skins2/x11/x11_window.hpp b/modules/gui/skins2/x11/x11_window.hpp index 186a8c2ede..f20b06daf1 100644 --- a/modules/gui/skins2/x11/x11_window.hpp +++ b/modules/gui/skins2/x11/x11_window.hpp @@ -65,11 +65,22 @@ class X11Window: public OSWindow /// Get the window ID Window getDrawable() const { return m_wnd; } + /// Getter for the handler + void* getOSHandle() const { return (void*) m_wnd; } + + /// Getter for the handler + void* getParentOSHandle() const { return (void*) m_wnd_parent; } + + /// reparent the window + void reparent( void* OSHandle, int x, int y, int w, int h ); + private: /// X11 display X11Display &m_rDisplay; /// Window ID Window m_wnd; + /// Window ID + Window m_wnd_parent; /// Parent window X11Window *m_pParent; /// Indicates whether the window handles drag&drop events