Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

window_manager.cpp

00001 /*****************************************************************************
00002  * window_manager.cpp
00003  *****************************************************************************
00004  * Copyright (C) 2003 the VideoLAN team
00005  * $Id: window_manager.cpp 12912 2005-10-22 11:57:29Z asmax $
00006  *
00007  * Authors: Cyril Deguet     <[email protected]>
00008  *          Olivier Teulière <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 #include "window_manager.hpp"
00026 #include "generic_layout.hpp"
00027 #include "generic_window.hpp"
00028 #include "os_factory.hpp"
00029 #include "anchor.hpp"
00030 #include "tooltip.hpp"
00031 #include "../utils/position.hpp"
00032 #include "../src/var_manager.hpp"
00033 
00034 
00035 WindowManager::WindowManager( intf_thread_t *pIntf ):
00036     SkinObject( pIntf ), m_magnet( 0 ), m_pTooltip( NULL )
00037 {
00038     // Create and register a variable for the "on top" status
00039     VarManager *pVarManager = VarManager::instance( getIntf() );
00040     m_cVarOnTop = VariablePtr( new VarBoolImpl( getIntf() ) );
00041     pVarManager->registerVar( m_cVarOnTop, "vlc.isOnTop" );
00042 }
00043 
00044 
00045 WindowManager::~WindowManager()
00046 {
00047     delete m_pTooltip;
00048 }
00049 
00050 
00051 void WindowManager::registerWindow( TopWindow &rWindow )
00052 {
00053     // Add the window to the set
00054     m_allWindows.insert( &rWindow );
00055 }
00056 
00057 
00058 void WindowManager::unregisterWindow( TopWindow &rWindow )
00059 {
00060     // Erase every possible reference to the window
00061     m_allWindows.erase( &rWindow );
00062     m_movingWindows.erase( &rWindow );
00063     m_dependencies.erase( &rWindow );
00064 }
00065 
00066 
00067 void WindowManager::startMove( TopWindow &rWindow )
00068 {
00069     // Rebuild the set of moving windows
00070     m_movingWindows.clear();
00071     buildDependSet( m_movingWindows, &rWindow );
00072 
00073 #ifdef WIN32
00074     if( config_GetInt( getIntf(), "skins2-transparency" ) )
00075     {
00076         // Change the opacity of the moving windows
00077         WinSet_t::const_iterator it;
00078         for( it = m_movingWindows.begin(); it != m_movingWindows.end(); it++ )
00079         {
00080             (*it)->setOpacity( m_moveAlpha );
00081         }
00082 
00083         // FIXME: We need to refresh the windows, because if 2 windows overlap
00084         // and one of them becomes transparent, the other one is not refreshed
00085         // automatically. I don't know why... -- Ipkiss
00086         for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
00087         {
00088             (*it)->refresh( 0, 0, (*it)->getWidth(), (*it)->getHeight() );
00089         }
00090     }
00091 #endif
00092 }
00093 
00094 
00095 void WindowManager::stopMove()
00096 {
00097     WinSet_t::const_iterator itWin1, itWin2;
00098     AncList_t::const_iterator itAnc1, itAnc2;
00099 
00100 #ifdef WIN32
00101     if( config_GetInt( getIntf(), "skins2-transparency" ) )
00102     {
00103         // Restore the opacity of the moving windows
00104         WinSet_t::const_iterator it;
00105         for( it = m_movingWindows.begin(); it != m_movingWindows.end(); it++ )
00106         {
00107             (*it)->setOpacity( m_alpha );
00108         }
00109     }
00110 #endif
00111 
00112     // Delete the dependencies
00113     m_dependencies.clear();
00114 
00115     // Now we rebuild the dependencies.
00116     // Iterate through all the windows
00117     for( itWin1 = m_allWindows.begin(); itWin1 != m_allWindows.end(); itWin1++ )
00118     {
00119         // Get the anchors of the layout associated to the window
00120         const AncList_t &ancList1 =
00121             (*itWin1)->getActiveLayout().getAnchorList();
00122 
00123         // Iterate through all the windows, starting with (*itWin1)
00124         for( itWin2 = itWin1; itWin2 != m_allWindows.end(); itWin2++ )
00125         {
00126             // A window can't anchor itself...
00127             if( (*itWin2) == (*itWin1) )
00128                 continue;
00129 
00130             // Now, check for anchoring between the 2 windows
00131             const AncList_t &ancList2 =
00132                 (*itWin2)->getActiveLayout().getAnchorList();
00133             for( itAnc1 = ancList1.begin(); itAnc1 != ancList1.end(); itAnc1++ )
00134             {
00135                 for( itAnc2 = ancList2.begin();
00136                      itAnc2 != ancList2.end(); itAnc2++ )
00137                 {
00138                     if( (*itAnc1)->isHanging( **itAnc2 ) )
00139                     {
00140                         // (*itWin1) anchors (*itWin2)
00141                         m_dependencies[*itWin1].insert( *itWin2 );
00142                     }
00143                     else if( (*itAnc2)->isHanging( **itAnc1 ) )
00144                     {
00145                         // (*itWin2) anchors (*itWin1)
00146                         m_dependencies[*itWin2].insert( *itWin1 );
00147                     }
00148                 }
00149             }
00150         }
00151     }
00152 }
00153 
00154 
00155 void WindowManager::move( TopWindow &rWindow, int left, int top ) const
00156 {
00157     // Compute the real move offset
00158     int xOffset = left - rWindow.getLeft();
00159     int yOffset = top - rWindow.getTop();
00160 
00161     // Check anchoring; this can change the values of xOffset and yOffset
00162     checkAnchors( &rWindow, xOffset, yOffset );
00163 
00164     // Move all the windows
00165     WinSet_t::const_iterator it;
00166     for( it = m_movingWindows.begin(); it != m_movingWindows.end(); it++ )
00167     {
00168         (*it)->move( (*it)->getLeft() + xOffset, (*it)->getTop() + yOffset );
00169     }
00170 }
00171 
00172 
00173 void WindowManager::synchVisibility() const
00174 {
00175     WinSet_t::const_iterator it;
00176     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
00177     {
00178         // Show the window if it has to be visible
00179         if( (*it)->getVisibleVar().get() )
00180         {
00181             (*it)->innerShow();
00182         }
00183     }
00184 }
00185 
00186 
00187 void WindowManager::raiseAll() const
00188 {
00189     // Raise all the windows
00190     WinSet_t::const_iterator it;
00191     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
00192     {
00193         (*it)->raise();
00194     }
00195 }
00196 
00197 
00198 void WindowManager::showAll( bool firstTime ) const
00199 {
00200     // Show all the windows
00201     WinSet_t::const_iterator it;
00202     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
00203     {
00204         // When the theme is opened for the first time,
00205         // only show the window if set as visible in the XML
00206         if ((*it)->isVisible() || !firstTime)
00207         {
00208             (*it)->show();
00209         }
00210         (*it)->setOpacity( m_alpha );
00211     }
00212 }
00213 
00214 
00215 void WindowManager::hideAll() const
00216 {
00217     WinSet_t::const_iterator it;
00218     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
00219     {
00220         (*it)->hide();
00221     }
00222 }
00223 
00224 
00225 void WindowManager::toggleOnTop()
00226 {
00227     // Update the boolean variable
00228     VarBoolImpl *pVarOnTop = (VarBoolImpl*)m_cVarOnTop.get();
00229     pVarOnTop->set( !pVarOnTop->get() );
00230 
00231     // Toggle the "on top" status
00232     WinSet_t::const_iterator it;
00233     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
00234     {
00235         (*it)->toggleOnTop( pVarOnTop->get() );
00236     }
00237 }
00238 
00239 
00240 void WindowManager::buildDependSet( WinSet_t &rWinSet,
00241                                     TopWindow *pWindow )
00242 {
00243     // pWindow is in the set
00244     rWinSet.insert( pWindow );
00245 
00246     // Iterate through the anchored windows
00247     const WinSet_t &anchored = m_dependencies[pWindow];
00248     WinSet_t::const_iterator iter;
00249     for( iter = anchored.begin(); iter != anchored.end(); iter++ )
00250     {
00251         // Check that the window isn't already in the set before adding it
00252         if( rWinSet.find( *iter ) == rWinSet.end() )
00253         {
00254             buildDependSet( rWinSet, *iter );
00255         }
00256     }
00257 }
00258 
00259 
00260 void WindowManager::checkAnchors( TopWindow *pWindow,
00261                                   int &xOffset, int &yOffset ) const
00262 {
00263     WinSet_t::const_iterator itMov, itSta;
00264     AncList_t::const_iterator itAncMov, itAncSta;
00265 
00266     // Check magnetism with screen edges first (actually it is the work area)
00267     Rect workArea = OSFactory::instance( getIntf() )->getWorkArea();
00268     // Iterate through the moving windows
00269     for( itMov = m_movingWindows.begin();
00270          itMov != m_movingWindows.end(); itMov++ )
00271     {
00272         // Skip the invisible windows
00273         if( ! (*itMov)->getVisibleVar().get() )
00274         {
00275             continue;
00276         }
00277 
00278         int newLeft = (*itMov)->getLeft() + xOffset;
00279         int newTop = (*itMov)->getTop() + yOffset;
00280         if( newLeft > workArea.getLeft() - m_magnet &&
00281             newLeft < workArea.getLeft() + m_magnet )
00282         {
00283             xOffset = workArea.getLeft() - (*itMov)->getLeft();
00284         }
00285         if( newTop > workArea.getTop() - m_magnet &&
00286             newTop < workArea.getTop() + m_magnet )
00287         {
00288             yOffset = workArea.getTop() - (*itMov)->getTop();
00289         }
00290         if( newLeft + (*itMov)->getWidth() > workArea.getRight() - m_magnet &&
00291             newLeft + (*itMov)->getWidth() < workArea.getRight() + m_magnet )
00292         {
00293             xOffset = workArea.getRight() - (*itMov)->getLeft()
00294                       - (*itMov)->getWidth();
00295         }
00296         if( newTop + (*itMov)->getHeight() > workArea.getBottom() - m_magnet &&
00297             newTop + (*itMov)->getHeight() <  workArea.getBottom() + m_magnet )
00298         {
00299             yOffset =  workArea.getBottom() - (*itMov)->getTop()
00300                        - (*itMov)->getHeight();
00301         }
00302     }
00303 
00304     // Iterate through the moving windows
00305     for( itMov = m_movingWindows.begin();
00306          itMov != m_movingWindows.end(); itMov++ )
00307     {
00308         // Skip the invisible windows
00309         if( ! (*itMov)->getVisibleVar().get() )
00310         {
00311             continue;
00312         }
00313 
00314         // Get the anchors in the main layout of this moving window
00315         const AncList_t &movAnchors =
00316             (*itMov)->getActiveLayout().getAnchorList();
00317 
00318         // Iterate through the static windows
00319         for( itSta = m_allWindows.begin();
00320              itSta != m_allWindows.end(); itSta++ )
00321         {
00322             // Skip the moving windows and the invisible ones
00323             if( m_movingWindows.find( (*itSta) ) != m_movingWindows.end() ||
00324                 ! (*itSta)->getVisibleVar().get() )
00325             {
00326                 continue;
00327             }
00328 
00329             // Get the anchors in the main layout of this static window
00330             const AncList_t &staAnchors =
00331                 (*itSta)->getActiveLayout().getAnchorList();
00332 
00333             // Check if there is an anchoring between one of the movAnchors
00334             // and one of the staAnchors
00335             for( itAncMov = movAnchors.begin();
00336                  itAncMov != movAnchors.end(); itAncMov++ )
00337             {
00338                 for( itAncSta = staAnchors.begin();
00339                      itAncSta != staAnchors.end(); itAncSta++ )
00340                 {
00341                     if( (*itAncSta)->canHang( **itAncMov, xOffset, yOffset ) )
00342                     {
00343                         // We have found an anchoring!
00344                         // There is nothing to do here, since xOffset and
00345                         // yOffset are automatically modified by canHang()
00346 
00347                         // Don't check the other anchors, one is enough...
00348                         return;
00349                     }
00350                     else
00351                     {
00352                         // Temporary variables
00353                         int xOffsetTemp = -xOffset;
00354                         int yOffsetTemp = -yOffset;
00355                         if( (*itAncMov)->canHang( **itAncSta, xOffsetTemp,
00356                                                   yOffsetTemp ) )
00357                         {
00358                             // We have found an anchoring!
00359                             // xOffsetTemp and yOffsetTemp have been updated,
00360                             // we just need to change xOffset and yOffset
00361                             xOffset = -xOffsetTemp;
00362                             yOffset = -yOffsetTemp;
00363 
00364                             // Don't check the other anchors, one is enough...
00365                             return;
00366                         }
00367                     }
00368                 }
00369             }
00370         }
00371     }
00372 }
00373 
00374 
00375 void WindowManager::createTooltip( const GenericFont &rTipFont )
00376 {
00377     // Create the tooltip window
00378     if( !m_pTooltip )
00379     {
00380         m_pTooltip = new Tooltip( getIntf(), rTipFont, 500 );
00381     }
00382     else
00383     {
00384         msg_Warn( getIntf(), "Tooltip already created!");
00385     }
00386 }
00387 
00388 
00389 void WindowManager::showTooltip()
00390 {
00391     if( m_pTooltip )
00392     {
00393         m_pTooltip->show();
00394     }
00395 }
00396 
00397 
00398 void WindowManager::hideTooltip()
00399 {
00400     if( m_pTooltip )
00401     {
00402         m_pTooltip->hide();
00403     }
00404 }
00405 
00406 
00407 void WindowManager::addLayout( TopWindow &rWindow, GenericLayout &rLayout )
00408 {
00409     rWindow.setActiveLayout( &rLayout );
00410 }
00411 
00412 
00413 void WindowManager::setActiveLayout( TopWindow &rWindow,
00414                                      GenericLayout &rLayout )
00415 {
00416     rWindow.setActiveLayout( &rLayout );
00417     // Rebuild the dependencies
00418     stopMove();
00419 }

Generated on Tue Dec 20 10:14:43 2005 for vlc-0.8.4a by  doxygen 1.4.2