window_manager.cpp
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:20k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * window_manager.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2003 the VideoLAN team
  5.  * $Id: 01385b5682af2d34042e11638a5c429b18bee4c4 $
  6.  *
  7.  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
  8.  *          Olivier Teulière <ipkiss@via.ecp.fr>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. #include "window_manager.hpp"
  25. #include "generic_layout.hpp"
  26. #include "generic_window.hpp"
  27. #include "os_factory.hpp"
  28. #include "anchor.hpp"
  29. #include "tooltip.hpp"
  30. #include "var_manager.hpp"
  31. WindowManager::WindowManager( intf_thread_t *pIntf ):
  32.     SkinObject( pIntf ), m_magnet( 0 ), m_direction( kNone ),
  33.     m_maximizeRect(0, 0, 50, 50),
  34.     m_pTooltip( NULL ), m_pPopup( NULL )
  35. {
  36.     // Create and register a variable for the "on top" status
  37.     VarManager *pVarManager = VarManager::instance( getIntf() );
  38.     m_cVarOnTop = VariablePtr( new VarBoolImpl( getIntf() ) );
  39.     pVarManager->registerVar( m_cVarOnTop, "vlc.isOnTop" );
  40. }
  41. WindowManager::~WindowManager()
  42. {
  43.     delete m_pTooltip;
  44. }
  45. void WindowManager::registerWindow( TopWindow &rWindow )
  46. {
  47.     // Add the window to the set
  48.     m_allWindows.insert( &rWindow );
  49. }
  50. void WindowManager::unregisterWindow( TopWindow &rWindow )
  51. {
  52.     // Erase every possible reference to the window
  53.     m_allWindows.erase( &rWindow );
  54.     m_movingWindows.erase( &rWindow );
  55.     m_dependencies.erase( &rWindow );
  56. }
  57. void WindowManager::startMove( TopWindow &rWindow )
  58. {
  59.     // Rebuild the set of moving windows
  60.     m_movingWindows.clear();
  61.     buildDependSet( m_movingWindows, &rWindow );
  62. #ifdef WIN32
  63.     if( config_GetInt( getIntf(), "skins2-transparency" ) )
  64.     {
  65.         // Change the opacity of the moving windows
  66.         WinSet_t::const_iterator it;
  67.         for( it = m_movingWindows.begin(); it != m_movingWindows.end(); it++ )
  68.         {
  69.             (*it)->setOpacity( m_moveAlpha );
  70.         }
  71.         // FIXME: We need to refresh the windows, because if 2 windows overlap
  72.         // and one of them becomes transparent, the other one is not refreshed
  73.         // automatically. I don't know why... -- Ipkiss
  74.         for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
  75.         {
  76.             (*it)->refresh( 0, 0, (*it)->getWidth(), (*it)->getHeight() );
  77.         }
  78.     }
  79. #endif
  80. }
  81. void WindowManager::stopMove()
  82. {
  83.     WinSet_t::const_iterator itWin1, itWin2;
  84.     AncList_t::const_iterator itAnc1, itAnc2;
  85. #ifdef WIN32
  86.     if( config_GetInt( getIntf(), "skins2-transparency" ) )
  87.     {
  88.         // Restore the opacity of the moving windows
  89.         WinSet_t::const_iterator it;
  90.         for( it = m_movingWindows.begin(); it != m_movingWindows.end(); it++ )
  91.         {
  92.             (*it)->setOpacity( m_alpha );
  93.         }
  94.     }
  95. #endif
  96.     // Delete the dependencies
  97.     m_dependencies.clear();
  98.     // Now we rebuild the dependencies.
  99.     // Iterate through all the windows
  100.     for( itWin1 = m_allWindows.begin(); itWin1 != m_allWindows.end(); itWin1++ )
  101.     {
  102.         // Get the anchors of the layout associated to the window
  103.         const AncList_t &ancList1 =
  104.             (*itWin1)->getActiveLayout().getAnchorList();
  105.         // Iterate through all the windows, starting with (*itWin1)
  106.         for( itWin2 = itWin1; itWin2 != m_allWindows.end(); itWin2++ )
  107.         {
  108.             // A window can't anchor itself...
  109.             if( (*itWin2) == (*itWin1) )
  110.                 continue;
  111.             // Now, check for anchoring between the 2 windows
  112.             const AncList_t &ancList2 =
  113.                 (*itWin2)->getActiveLayout().getAnchorList();
  114.             for( itAnc1 = ancList1.begin(); itAnc1 != ancList1.end(); itAnc1++ )
  115.             {
  116.                 for( itAnc2 = ancList2.begin();
  117.                      itAnc2 != ancList2.end(); itAnc2++ )
  118.                 {
  119.                     if( (*itAnc1)->isHanging( **itAnc2 ) )
  120.                     {
  121.                         // (*itWin1) anchors (*itWin2)
  122.                         m_dependencies[*itWin1].insert( *itWin2 );
  123.                     }
  124.                     else if( (*itAnc2)->isHanging( **itAnc1 ) )
  125.                     {
  126.                         // (*itWin2) anchors (*itWin1)
  127.                         m_dependencies[*itWin2].insert( *itWin1 );
  128.                     }
  129.                 }
  130.             }
  131.         }
  132.     }
  133. }
  134. void WindowManager::move( TopWindow &rWindow, int left, int top ) const
  135. {
  136.     // Compute the real move offset
  137.     int xOffset = left - rWindow.getLeft();
  138.     int yOffset = top - rWindow.getTop();
  139.     // Check anchoring; this can change the values of xOffset and yOffset
  140.     checkAnchors( &rWindow, xOffset, yOffset );
  141.     // Move all the windows
  142.     WinSet_t::const_iterator it;
  143.     for( it = m_movingWindows.begin(); it != m_movingWindows.end(); it++ )
  144.     {
  145.         (*it)->move( (*it)->getLeft() + xOffset, (*it)->getTop() + yOffset );
  146.     }
  147. }
  148. void WindowManager::startResize( GenericLayout &rLayout, Direction_t direction )
  149. {
  150.     m_direction = direction;
  151.     // Rebuild the set of moving windows.
  152.     // From the resized window, we only take into account the anchors which
  153.     // are mobile with the current type of resizing, and that are hanging a
  154.     // window. The hanged windows will come will all their dependencies.
  155.     m_resizeMovingE.clear();
  156.     m_resizeMovingS.clear();
  157.     m_resizeMovingSE.clear();
  158.     WinSet_t::const_iterator itWin;
  159.     AncList_t::const_iterator itAnc1, itAnc2;
  160.     // Get the anchors of the layout
  161.     const AncList_t &ancList1 = rLayout.getAnchorList();
  162.     // Iterate through all the hanged windows
  163.     for( itWin = m_dependencies[rLayout.getWindow()].begin();
  164.          itWin != m_dependencies[rLayout.getWindow()].end(); itWin++ )
  165.     {
  166.         // Now, check for anchoring between the 2 windows
  167.         const AncList_t &ancList2 =
  168.             (*itWin)->getActiveLayout().getAnchorList();
  169.         for( itAnc1 = ancList1.begin(); itAnc1 != ancList1.end(); itAnc1++ )
  170.         {
  171.             for( itAnc2 = ancList2.begin();
  172.                  itAnc2 != ancList2.end(); itAnc2++ )
  173.             {
  174.                 if( (*itAnc1)->isHanging( **itAnc2 ) )
  175.                 {
  176.                     // Add the dependencies of the hanged window to one of the
  177.                     // lists of moving windows
  178.                     Position::Ref_t aRefPos =
  179.                         (*itAnc1)->getPosition().getRefLeftTop();
  180.                     if( aRefPos == Position::kRightTop )
  181.                         buildDependSet( m_resizeMovingE, *itWin );
  182.                     else if( aRefPos == Position::kLeftBottom )
  183.                         buildDependSet( m_resizeMovingS, *itWin );
  184.                     else if( aRefPos == Position::kRightBottom )
  185.                         buildDependSet( m_resizeMovingSE, *itWin );
  186.                     break;
  187.                 }
  188.             }
  189.         }
  190.     }
  191.     // The checkAnchors() method will need to have m_movingWindows properly set
  192.     // so let's insert in it the contents of the other sets
  193.     m_movingWindows.clear();
  194.     m_movingWindows.insert( rLayout.getWindow() );
  195.     m_movingWindows.insert( m_resizeMovingE.begin(), m_resizeMovingE.end() );
  196.     m_movingWindows.insert( m_resizeMovingS.begin(), m_resizeMovingS.end() );
  197.     m_movingWindows.insert( m_resizeMovingSE.begin(), m_resizeMovingSE.end() );
  198. }
  199. void WindowManager::stopResize()
  200. {
  201.     // Nothing different from stopMove(), luckily
  202.     stopMove();
  203. }
  204. void WindowManager::resize( GenericLayout &rLayout,
  205.                             int width, int height ) const
  206. {
  207.     // TODO: handle anchored windows
  208.     // Compute the real resizing offset
  209.     int xOffset = width - rLayout.getWidth();
  210.     int yOffset = height - rLayout.getHeight();
  211.     // Check anchoring; this can change the values of xOffset and yOffset
  212.     checkAnchors( rLayout.getWindow(), xOffset, yOffset );
  213.     if( m_direction == kResizeS )
  214.         xOffset = 0;
  215.     if( m_direction == kResizeE )
  216.         yOffset = 0;
  217.     int newWidth = rLayout.getWidth() + xOffset;
  218.     int newHeight = rLayout.getHeight() + yOffset;
  219.     // Check boundaries
  220.     if( newWidth < rLayout.getMinWidth() )
  221.     {
  222.         newWidth = rLayout.getMinWidth();
  223.     }
  224.     if( newWidth > rLayout.getMaxWidth() )
  225.     {
  226.         newWidth = rLayout.getMaxWidth();
  227.     }
  228.     if( newHeight < rLayout.getMinHeight() )
  229.     {
  230.         newHeight = rLayout.getMinHeight();
  231.     }
  232.     if( newHeight > rLayout.getMaxHeight() )
  233.     {
  234.         newHeight = rLayout.getMaxHeight();
  235.     }
  236.     if( newWidth == rLayout.getWidth() && newHeight == rLayout.getHeight() )
  237.     {
  238.         return;
  239.     }
  240.     // New offset, after the last corrections
  241.     int xNewOffset = newWidth - rLayout.getWidth();
  242.     int yNewOffset = newHeight - rLayout.getHeight();
  243.     // Do the actual resizing
  244.     rLayout.resize( newWidth, newHeight );
  245.     // Move all the anchored windows
  246.     WinSet_t::const_iterator it;
  247.     if( m_direction == kResizeE ||
  248.         m_direction == kResizeSE )
  249.     {
  250.         for( it = m_resizeMovingE.begin(); it != m_resizeMovingE.end(); it++ )
  251.         {
  252.             (*it)->move( (*it)->getLeft() + xNewOffset,
  253.                          (*it)->getTop() );
  254.         }
  255.     }
  256.     if( m_direction == kResizeE ||
  257.         m_direction == kResizeSE )
  258.     {
  259.         for( it = m_resizeMovingS.begin(); it != m_resizeMovingS.end(); it++ )
  260.         {
  261.             (*it)->move( (*it)->getLeft(),
  262.                          (*it)->getTop( )+ yNewOffset );
  263.         }
  264.     }
  265.     if( m_direction == kResizeE ||
  266.         m_direction == kResizeS ||
  267.         m_direction == kResizeSE )
  268.     {
  269.         for( it = m_resizeMovingSE.begin(); it != m_resizeMovingSE.end(); it++ )
  270.         {
  271.             (*it)->move( (*it)->getLeft() + xNewOffset,
  272.                          (*it)->getTop() + yNewOffset );
  273.         }
  274.     }
  275. }
  276. void WindowManager::maximize( TopWindow &rWindow )
  277. {
  278.     // Save the current position/size of the window, to be able to restore it
  279.     m_maximizeRect = SkinsRect( rWindow.getLeft(), rWindow.getTop(),
  280.                                rWindow.getLeft() + rWindow.getWidth(),
  281.                                rWindow.getTop() + rWindow.getHeight() );
  282.     SkinsRect workArea = OSFactory::instance( getIntf() )->getWorkArea();
  283.     // Move the window
  284.     startMove( rWindow );
  285.     move( rWindow, workArea.getLeft(), workArea.getTop() );
  286.     stopMove();
  287.     // Now resize it
  288.     // FIXME: Ugly const_cast
  289.     GenericLayout &rLayout = (GenericLayout&)rWindow.getActiveLayout();
  290.     startResize( rLayout, kResizeSE );
  291.     resize( rLayout, workArea.getWidth(), workArea.getHeight() );
  292.     stopResize();
  293.     rWindow.m_pVarMaximized->set( true );
  294.     // Make the window unmovable by unregistering it
  295. //     unregisterWindow( rWindow );
  296. }
  297. void WindowManager::unmaximize( TopWindow &rWindow )
  298. {
  299.     // Register the window to allow moving it
  300. //     registerWindow( rWindow );
  301.     // Resize the window
  302.     // FIXME: Ugly const_cast
  303.     GenericLayout &rLayout = (GenericLayout&)rWindow.getActiveLayout();
  304.     startResize( rLayout, kResizeSE );
  305.     resize( rLayout, m_maximizeRect.getWidth(), m_maximizeRect.getHeight() );
  306.     stopResize();
  307.     // Now move it
  308.     startMove( rWindow );
  309.     move( rWindow, m_maximizeRect.getLeft(), m_maximizeRect.getTop() );
  310.     stopMove();
  311.     rWindow.m_pVarMaximized->set( false );
  312. }
  313. void WindowManager::synchVisibility() const
  314. {
  315.     WinSet_t::const_iterator it;
  316.     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
  317.     {
  318.         // Show the window if it has to be visible
  319.         if( (*it)->getVisibleVar().get() )
  320.         {
  321.             (*it)->innerShow();
  322.         }
  323.     }
  324. }
  325. void WindowManager::saveVisibility()
  326. {
  327.     WinSet_t::const_iterator it;
  328.     m_savedWindows.clear();
  329.     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
  330.     {
  331.         // Remember the window if it is visible
  332.         if( (*it)->getVisibleVar().get() )
  333.         {
  334.             m_savedWindows.insert( *it );
  335.         }
  336.     }
  337. }
  338. void WindowManager::restoreVisibility() const
  339. {
  340.     // Warning in case we never called saveVisibility()
  341.     if( m_savedWindows.size() == 0 )
  342.     {
  343.         msg_Warn( getIntf(), "restoring visibility for no window" );
  344.     }
  345.     WinSet_t::const_iterator it;
  346.     for( it = m_savedWindows.begin(); it != m_savedWindows.end(); it++)
  347.     {
  348.         (*it)->show();
  349.     }
  350. }
  351. void WindowManager::raiseAll() const
  352. {
  353.     // Raise all the windows
  354.     WinSet_t::const_iterator it;
  355.     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
  356.     {
  357.         (*it)->raise();
  358.     }
  359. }
  360. void WindowManager::showAll( bool firstTime ) const
  361. {
  362.     // Show all the windows
  363.     WinSet_t::const_iterator it;
  364.     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
  365.     {
  366.         // When the theme is opened for the first time,
  367.         // only show the window if set as visible in the XML
  368.         if( (*it)->isVisible() || !firstTime )
  369.         {
  370.             (*it)->show();
  371.         }
  372.         (*it)->setOpacity( m_alpha );
  373.     }
  374. }
  375. void WindowManager::hideAll() const
  376. {
  377.     WinSet_t::const_iterator it;
  378.     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
  379.     {
  380.         (*it)->hide();
  381.     }
  382. }
  383. void WindowManager::toggleOnTop()
  384. {
  385.     // Update the boolean variable
  386.     VarBoolImpl *pVarOnTop = (VarBoolImpl*)m_cVarOnTop.get();
  387.     pVarOnTop->set( !pVarOnTop->get() );
  388.     // Toggle the "on top" status
  389.     WinSet_t::const_iterator it;
  390.     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
  391.     {
  392.         (*it)->toggleOnTop( pVarOnTop->get() );
  393.     }
  394. }
  395. void WindowManager::buildDependSet( WinSet_t &rWinSet,
  396.                                     TopWindow *pWindow )
  397. {
  398.     // pWindow is in the set
  399.     rWinSet.insert( pWindow );
  400.     // Iterate through the anchored windows
  401.     const WinSet_t &anchored = m_dependencies[pWindow];
  402.     WinSet_t::const_iterator iter;
  403.     for( iter = anchored.begin(); iter != anchored.end(); iter++ )
  404.     {
  405.         // Check that the window isn't already in the set before adding it
  406.         if( rWinSet.find( *iter ) == rWinSet.end() )
  407.         {
  408.             buildDependSet( rWinSet, *iter );
  409.         }
  410.     }
  411. }
  412. void WindowManager::checkAnchors( TopWindow *pWindow,
  413.                                   int &xOffset, int &yOffset ) const
  414. {
  415.     WinSet_t::const_iterator itMov, itSta;
  416.     AncList_t::const_iterator itAncMov, itAncSta;
  417.     // Check magnetism with screen edges first (actually it is the work area)
  418.     SkinsRect workArea = OSFactory::instance( getIntf() )->getWorkArea();
  419.     // Iterate through the moving windows
  420.     for( itMov = m_movingWindows.begin();
  421.          itMov != m_movingWindows.end(); itMov++ )
  422.     {
  423.         // Skip the invisible windows
  424.         if( ! (*itMov)->getVisibleVar().get() )
  425.         {
  426.             continue;
  427.         }
  428.         int newLeft = (*itMov)->getLeft() + xOffset;
  429.         int newTop = (*itMov)->getTop() + yOffset;
  430.         if( newLeft > workArea.getLeft() - m_magnet &&
  431.             newLeft < workArea.getLeft() + m_magnet )
  432.         {
  433.             xOffset = workArea.getLeft() - (*itMov)->getLeft();
  434.         }
  435.         if( newTop > workArea.getTop() - m_magnet &&
  436.             newTop < workArea.getTop() + m_magnet )
  437.         {
  438.             yOffset = workArea.getTop() - (*itMov)->getTop();
  439.         }
  440.         int right = workArea.getLeft() + workArea.getWidth();
  441.         if( newLeft + (*itMov)->getWidth() > right - m_magnet &&
  442.             newLeft + (*itMov)->getWidth() < right + m_magnet )
  443.         {
  444.             xOffset = right - (*itMov)->getLeft() - (*itMov)->getWidth();
  445.         }
  446.         int bottom = workArea.getTop() + workArea.getHeight();
  447.         if( newTop + (*itMov)->getHeight() > bottom - m_magnet &&
  448.             newTop + (*itMov)->getHeight() <  bottom + m_magnet )
  449.         {
  450.             yOffset =  bottom - (*itMov)->getTop() - (*itMov)->getHeight();
  451.         }
  452.     }
  453.     // Iterate through the moving windows
  454.     for( itMov = m_movingWindows.begin();
  455.          itMov != m_movingWindows.end(); itMov++ )
  456.     {
  457.         // Skip the invisible windows
  458.         if( ! (*itMov)->getVisibleVar().get() )
  459.         {
  460.             continue;
  461.         }
  462.         // Get the anchors in the main layout of this moving window
  463.         const AncList_t &movAnchors =
  464.             (*itMov)->getActiveLayout().getAnchorList();
  465.         // Iterate through the static windows
  466.         for( itSta = m_allWindows.begin();
  467.              itSta != m_allWindows.end(); itSta++ )
  468.         {
  469.             // Skip the moving windows and the invisible ones
  470.             if( m_movingWindows.find( (*itSta) ) != m_movingWindows.end() ||
  471.                 ! (*itSta)->getVisibleVar().get() )
  472.             {
  473.                 continue;
  474.             }
  475.             // Get the anchors in the main layout of this static window
  476.             const AncList_t &staAnchors =
  477.                 (*itSta)->getActiveLayout().getAnchorList();
  478.             // Check if there is an anchoring between one of the movAnchors
  479.             // and one of the staAnchors
  480.             for( itAncMov = movAnchors.begin();
  481.                  itAncMov != movAnchors.end(); itAncMov++ )
  482.             {
  483.                 for( itAncSta = staAnchors.begin();
  484.                      itAncSta != staAnchors.end(); itAncSta++ )
  485.                 {
  486.                     if( (*itAncSta)->canHang( **itAncMov, xOffset, yOffset ) )
  487.                     {
  488.                         // We have found an anchoring!
  489.                         // There is nothing to do here, since xOffset and
  490.                         // yOffset are automatically modified by canHang()
  491.                         // Don't check the other anchors, one is enough...
  492.                         return;
  493.                     }
  494.                     else
  495.                     {
  496.                         // Temporary variables
  497.                         int xOffsetTemp = -xOffset;
  498.                         int yOffsetTemp = -yOffset;
  499.                         if( (*itAncMov)->canHang( **itAncSta, xOffsetTemp,
  500.                                                   yOffsetTemp ) )
  501.                         {
  502.                             // We have found an anchoring!
  503.                             // xOffsetTemp and yOffsetTemp have been updated,
  504.                             // we just need to change xOffset and yOffset
  505.                             xOffset = -xOffsetTemp;
  506.                             yOffset = -yOffsetTemp;
  507.                             // Don't check the other anchors, one is enough...
  508.                             return;
  509.                         }
  510.                     }
  511.                 }
  512.             }
  513.         }
  514.     }
  515. }
  516. void WindowManager::createTooltip( const GenericFont &rTipFont )
  517. {
  518.     // Create the tooltip window
  519.     if( !m_pTooltip )
  520.     {
  521.         m_pTooltip = new Tooltip( getIntf(), rTipFont, 500 );
  522.     }
  523.     else
  524.     {
  525.         msg_Warn( getIntf(), "tooltip already created!" );
  526.     }
  527. }
  528. void WindowManager::showTooltip()
  529. {
  530.     if( m_pTooltip )
  531.     {
  532.         m_pTooltip->show();
  533.     }
  534. }
  535. void WindowManager::hideTooltip()
  536. {
  537.     if( m_pTooltip )
  538.     {
  539.         m_pTooltip->hide();
  540.     }
  541. }
  542. void WindowManager::addLayout( TopWindow &rWindow, GenericLayout &rLayout )
  543. {
  544.     rWindow.setActiveLayout( &rLayout );
  545. }
  546. void WindowManager::setActiveLayout( TopWindow &rWindow,
  547.                                      GenericLayout &rLayout )
  548. {
  549.     rWindow.setActiveLayout( &rLayout );
  550.     // Rebuild the dependencies
  551.     stopMove();
  552. }