]> git.sesse.net Git - vlc/blob - modules/gui/skins2/src/window_manager.cpp
* all: brand new skins interface ( still _experimental_) for x11 and
[vlc] / modules / gui / skins2 / src / window_manager.cpp
1 /*****************************************************************************
2  * window_manager.cpp
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: window_manager.cpp,v 1.1 2004/01/03 23:31:34 asmax Exp $
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 #include "window_manager.hpp"
26 #include "generic_window.hpp"
27 #include "os_factory.hpp"
28 #include "anchor.hpp"
29 #include "../utils/position.hpp"
30
31
32 void WindowManager::registerWindow( GenericWindow *pWindow )
33 {
34     if( pWindow == NULL )
35     {
36         msg_Dbg( getIntf(), "WM: registering a NULL window" );
37         return;
38     }
39
40     // Add the window to the set
41     m_allWindows.insert( pWindow );
42 }
43
44
45 void WindowManager::unregisterWindow( GenericWindow *pWindow )
46 {
47     // Erase every possible reference to the window
48     m_allWindows.erase( pWindow );
49     m_movingWindows.erase( pWindow );
50     m_dependencies.erase( pWindow );
51 }
52
53
54 void WindowManager::startMove( GenericWindow *pWindow )
55 {
56     // Rebuild the set of moving windows
57     m_movingWindows.clear();
58     buildDependSet( m_movingWindows, pWindow );
59
60     // Change the opacity of the moving windows
61     WinSet_t::const_iterator it;
62     for( it = m_movingWindows.begin(); it != m_movingWindows.end(); it++ )
63     {
64         (*it)->setOpacity( m_moveAlpha );
65     }
66 }
67
68
69 void WindowManager::stopMove()
70 {
71     WinSet_t::const_iterator itWin1, itWin2;
72     AncList_t::const_iterator itAnc1, itAnc2;
73
74     // Restore the opacity of the moving windows
75     WinSet_t::const_iterator it;
76     for( it = m_movingWindows.begin(); it != m_movingWindows.end(); it++ )
77     {
78         (*it)->setOpacity( m_alpha );
79     }
80
81     // Delete the dependencies
82     m_dependencies.clear();
83
84     // Now we rebuild the dependencies.
85     // Iterate through all the windows
86     for( itWin1 = m_allWindows.begin(); itWin1 != m_allWindows.end(); itWin1++ )
87     {
88         // Get the anchors of the window
89         const AncList_t &ancList1 = (*itWin1)->getAnchorList();
90
91         // Iterate through all the windows, starting with (*itWin1)
92         for( itWin2 = itWin1; itWin2 != m_allWindows.end(); itWin2++ )
93         {
94             // A window can't anchor itself...
95             if( (*itWin2) == (*itWin1) )
96                 continue;
97
98             // Now, check for anchoring between the 2 windows
99             const AncList_t &ancList2 = (*itWin2)->getAnchorList();
100             for( itAnc1 = ancList1.begin(); itAnc1 != ancList1.end(); itAnc1++ )
101             {
102                 for( itAnc2 = ancList2.begin();
103                      itAnc2 != ancList2.end(); itAnc2++ )
104                 {
105                     if( (*itAnc1)->isHanging( **itAnc2 ) )
106                     {
107                         // (*itWin1) anchors (*itWin2)
108                         m_dependencies[*itWin1].insert( *itWin2 );
109                     }
110                     else if( (*itAnc2)->isHanging( **itAnc1 ) )
111                     {
112                         // (*itWin2) anchors (*itWin1)
113                         m_dependencies[*itWin2].insert( *itWin1 );
114                     }
115                 }
116             }
117         }
118     }
119 }
120
121
122 void WindowManager::move( GenericWindow *pWindow, int left, int top ) const
123 {
124     // Compute the real move offset
125     int xOffset = left - pWindow->getLeft();
126     int yOffset = top - pWindow->getTop();
127
128     // Check anchoring; this can change the values of xOffset and yOffset
129     checkAnchors( pWindow, xOffset, yOffset );
130
131     // Move all the windows
132     WinSet_t::const_iterator it;
133     for( it = m_movingWindows.begin(); it != m_movingWindows.end(); it++ )
134     {
135         (*it)->move( (*it)->getLeft() + xOffset, (*it)->getTop() + yOffset );
136     }
137 }
138
139
140 void WindowManager::raise( GenericWindow *pWindow )
141 {
142     // Build a set of windows anchored to pWindow
143     WinSet_t winSet;
144     buildDependSet( winSet, pWindow );
145
146     // Raise the windows in the set
147     WinSet_t::const_iterator iter;
148     for( iter = winSet.begin(); iter != winSet.end(); iter++ )
149     {
150         (*iter)->raise();
151     }
152 }
153
154
155 void WindowManager::showAll() const
156 {
157     WinSet_t::const_iterator it;
158     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
159     {
160         (*it)->show();
161         (*it)->setOpacity( m_alpha );
162     }
163 }
164
165
166 void WindowManager::hideAll() const
167 {
168     WinSet_t::const_iterator it;
169     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
170     {
171         (*it)->hide();
172     }
173 }
174
175
176 void WindowManager::toggleOnTop()
177 {
178     m_isOnTop = !m_isOnTop;
179     WinSet_t::const_iterator it;
180     for( it = m_allWindows.begin(); it != m_allWindows.end(); it++ )
181     {
182         (*it)->toggleOnTop( m_isOnTop );
183     }
184 }
185
186
187 void WindowManager::buildDependSet( WinSet_t &rWinSet,
188                                     GenericWindow *pWindow )
189 {
190     // pWindow is in the set
191     rWinSet.insert( pWindow );
192
193     // Iterate through the anchored windows
194     const WinSet_t &anchored = m_dependencies[pWindow];
195     WinSet_t::const_iterator iter;
196     for( iter = anchored.begin(); iter != anchored.end(); iter++ )
197     {
198         // Check that the window isn't already in the set before adding it
199         if( rWinSet.find( *iter ) == rWinSet.end() )
200         {
201             buildDependSet( rWinSet, *iter );
202         }
203     }
204 }
205
206
207 void WindowManager::checkAnchors( GenericWindow *pWindow,
208                                   int &xOffset, int &yOffset ) const
209 {
210     WinSet_t::const_iterator itMov, itSta;
211     AncList_t::const_iterator itAncMov, itAncSta;
212
213     // Check magnetism with screen edges first (actually it is the work area)
214     Rect workArea = OSFactory::instance( getIntf() )->getWorkArea();
215     // Iterate through the moving windows
216     for( itMov = m_movingWindows.begin();
217          itMov != m_movingWindows.end(); itMov++ )
218     {
219         int newLeft = (*itMov)->getLeft() + xOffset;
220         int newTop = (*itMov)->getTop() + yOffset;
221         if( newLeft > workArea.getLeft() - m_magnet &&
222             newLeft < workArea.getLeft() + m_magnet )
223         {
224             xOffset = workArea.getLeft() - (*itMov)->getLeft();
225         }
226         if( newTop > workArea.getTop() - m_magnet &&
227             newTop < workArea.getTop() + m_magnet )
228         {
229             yOffset = workArea.getTop() - (*itMov)->getTop();
230         }
231         if( newLeft + (*itMov)->getWidth() > workArea.getRight() - m_magnet &&
232             newLeft + (*itMov)->getWidth() < workArea.getRight() + m_magnet )
233         {
234             xOffset = workArea.getRight() - (*itMov)->getLeft()
235                       - (*itMov)->getWidth();
236         }
237         if( newTop + (*itMov)->getHeight() > workArea.getBottom() - m_magnet &&
238             newTop + (*itMov)->getHeight() <  workArea.getBottom() + m_magnet )
239         {
240             yOffset =  workArea.getBottom() - (*itMov)->getTop()
241                        - (*itMov)->getHeight();
242         }
243     }
244
245     // Iterate through the moving windows
246     for( itMov = m_movingWindows.begin();
247          itMov != m_movingWindows.end(); itMov++ )
248     {
249         // Get the anchors of this moving window
250         const AncList_t &movAnchors = (*itMov)->getAnchorList();
251
252         // Iterate through the static windows
253         for( itSta = m_allWindows.begin();
254              itSta != m_allWindows.end(); itSta++ )
255         {
256             // Skip the moving windows
257             if( m_movingWindows.find( (*itSta) ) != m_movingWindows.end() )
258             {
259                 continue;
260             }
261
262             // Get the anchors of this static window
263             const AncList_t &staAnchors = (*itSta)->getAnchorList();
264
265             // Check if there is an anchoring between one of the movAnchors
266             // and one of the staAnchors
267             for( itAncMov = movAnchors.begin();
268                  itAncMov != movAnchors.end(); itAncMov++ )
269             {
270                 for( itAncSta = staAnchors.begin();
271                      itAncSta != staAnchors.end(); itAncSta++ )
272                 {
273                     if( (*itAncSta)->canHang( **itAncMov, xOffset, yOffset ) )
274                     {
275                         // We have found an anchoring!
276                         // There is nothing to do here, since xOffset and
277                         // yOffset are automatically modified by canHang()
278
279                         // Don't check the other anchors, one is enough...
280                         return;
281                     }
282                     else
283                     {
284                         // Temporary variables
285                         int xOffsetTemp = -xOffset;
286                         int yOffsetTemp = -yOffset;
287                         if( (*itAncMov)->canHang( **itAncSta, xOffsetTemp,
288                                                   yOffsetTemp ) )
289                         {
290                             // We have found an anchoring!
291                             // xOffsetTemp and yOffsetTemp have been updated,
292                             // we just need to change xOffset and yOffset
293                             xOffset = -xOffsetTemp;
294                             yOffset = -yOffsetTemp;
295
296                             // Don't check the other anchors, one is enough...
297                             return;
298                         }
299                     }
300                 }
301             }
302         }
303     }
304 }
305
306