1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 the VideoLAN team
7 * Authors: Cyril Deguet <asmax@via.ecp.fr>
8 * Olivier Teulière <ipkiss@via.ecp.fr>
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.
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.
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 *****************************************************************************/
25 #include "top_window.hpp"
26 #include "generic_layout.hpp"
27 #include "os_graphics.hpp"
28 #include "os_window.hpp"
29 #include "os_factory.hpp"
31 #include "var_manager.hpp"
32 #include "../commands/cmd_on_top.hpp"
33 #include "../commands/cmd_dialogs.hpp"
34 #include "../commands/cmd_add_item.hpp"
35 #include "../controls/ctrl_generic.hpp"
36 #include "../events/evt_refresh.hpp"
37 #include "../events/evt_enter.hpp"
38 #include "../events/evt_focus.hpp"
39 #include "../events/evt_leave.hpp"
40 #include "../events/evt_menu.hpp"
41 #include "../events/evt_motion.hpp"
42 #include "../events/evt_mouse.hpp"
43 #include "../events/evt_key.hpp"
44 #include "../events/evt_special.hpp"
45 #include "../events/evt_scroll.hpp"
46 #include "../events/evt_dragndrop.hpp"
47 #include "../utils/position.hpp"
48 #include "../utils/ustring.hpp"
51 #include <vlc_input.h>
56 TopWindow::TopWindow( intf_thread_t
*pIntf
, int left
, int top
,
57 WindowManager
&rWindowManager
,
58 bool dragDrop
, bool playOnDrop
, bool visible
,
59 GenericWindow::WindowType_t type
):
60 GenericWindow( pIntf
, left
, top
, dragDrop
, playOnDrop
, NULL
, type
),
61 m_initialVisibility( visible
), m_playOnDrop( playOnDrop
),
62 m_rWindowManager( rWindowManager
),
63 m_pActiveLayout( NULL
), m_pLastHitControl( NULL
),
64 m_pCapturingControl( NULL
), m_pFocusControl( NULL
),
65 m_pDragControl( NULL
), m_currModifier( 0 )
67 // Register as a moving window
68 m_rWindowManager
.registerWindow( *this );
70 // Create the "maximized" variable and register it in the manager
71 m_pVarMaximized
= new VarBoolImpl( pIntf
);
72 VarManager::instance( pIntf
)->registerVar( VariablePtr( m_pVarMaximized
) );
76 TopWindow::~TopWindow()
78 // Unregister from the window manager
79 m_rWindowManager
.unregisterWindow( *this );
83 void TopWindow::processEvent( EvtFocus
&rEvtFocus
)
89 void TopWindow::processEvent( EvtMenu
&rEvtMenu
)
91 Popup
*pPopup
= m_rWindowManager
.getActivePopup();
92 // We should never receive a menu event when there is no active popup!
95 msg_Warn( getIntf(), "unexpected menu event, ignoring" );
99 pPopup
->handleEvent( rEvtMenu
);
103 void TopWindow::processEvent( EvtMotion
&rEvtMotion
)
105 // New control hit by the mouse
106 CtrlGeneric
*pNewHitControl
=
107 findHitControl( rEvtMotion
.getXPos() - getLeft(),
108 rEvtMotion
.getYPos() - getTop() );
110 setLastHit( pNewHitControl
);
112 /// Update the help text
113 VarManager
*pVarManager
= VarManager::instance( getIntf() );
116 pVarManager
->getHelpText().set( pNewHitControl
->getHelpText() );
119 // Send a motion event to the hit control, or to the control
120 // that captured the mouse, if any
121 CtrlGeneric
*pActiveControl
= pNewHitControl
;
122 if( m_pCapturingControl
)
124 pActiveControl
= m_pCapturingControl
;
128 // Compute the coordinates relative to the window
129 int xPos
= rEvtMotion
.getXPos() - getLeft();
130 int yPos
= rEvtMotion
.getYPos() - getTop();
131 // Send a motion event
132 EvtMotion
evt( getIntf(), xPos
, yPos
);
133 pActiveControl
->handleEvent( evt
);
138 void TopWindow::processEvent( EvtLeave
&rEvtLeave
)
142 // No more hit control
144 if( !m_pCapturingControl
)
146 m_rWindowManager
.hideTooltip();
151 void TopWindow::processEvent( EvtMouse
&rEvtMouse
)
153 // Get the control hit by the mouse
154 CtrlGeneric
*pNewHitControl
= findHitControl( rEvtMouse
.getXPos(),
155 rEvtMouse
.getYPos() );
156 setLastHit( pNewHitControl
);
158 // Change the focused control
159 if( rEvtMouse
.getAction() == EvtMouse::kDown
)
162 m_rWindowManager
.raise( *this );
164 if( m_pFocusControl
!= pNewHitControl
)
166 if( m_pFocusControl
)
168 // The previous control loses the focus
169 EvtFocus
evt( getIntf(), false );
170 m_pFocusControl
->handleEvent( evt
);
171 m_pFocusControl
= NULL
;
174 if( pNewHitControl
&& pNewHitControl
->isFocusable() )
176 // The hit control gains the focus
177 m_pFocusControl
= pNewHitControl
;
178 EvtFocus
evt( getIntf(), true );
179 pNewHitControl
->handleEvent( evt
);
184 // Send a mouse event to the hit control, or to the control
185 // that captured the mouse, if any
186 CtrlGeneric
*pActiveControl
= pNewHitControl
;
187 if( m_pCapturingControl
)
189 pActiveControl
= m_pCapturingControl
;
193 pActiveControl
->handleEvent( rEvtMouse
);
198 void TopWindow::processEvent( EvtKey
&rEvtKey
)
200 // Forward the event to the focused control, if any
201 if( m_pFocusControl
)
203 m_pFocusControl
->handleEvent( rEvtKey
);
207 // Only do the action when the key is down
208 if( rEvtKey
.getKeyState() == EvtKey::kDown
)
210 getIntf()->p_sys
->p_dialogs
->sendKey( rEvtKey
.getModKey() );
213 // Always store the modifier, which can be needed for scroll events.
214 m_currModifier
= rEvtKey
.getMod();
217 void TopWindow::processEvent( EvtScroll
&rEvtScroll
)
222 // Get the control hit by the mouse
223 CtrlGeneric
*pNewHitControl
= findHitControl( rEvtScroll
.getXPos(),
224 rEvtScroll
.getYPos());
225 setLastHit( pNewHitControl
);
227 // send a mouse event to the right control when scrollable
228 // if none, send it directly to the vlc core
229 CtrlGeneric
*pHitControl
= m_pCapturingControl
?
230 m_pCapturingControl
: pNewHitControl
;
232 if( pHitControl
&& pHitControl
->isScrollable() )
234 pHitControl
->handleEvent( rEvtScroll
);
238 // Treat the scroll event as a hotkey plus current modifiers
239 int i
= (rEvtScroll
.getDirection() == EvtScroll::kUp
?
240 KEY_MOUSEWHEELUP
: KEY_MOUSEWHEELDOWN
) | m_currModifier
;
242 getIntf()->p_sys
->p_dialogs
->sendKey( i
);
246 void TopWindow::processEvent( EvtDragDrop
&rEvtDragDrop
)
248 // Get the control hit by the mouse
249 int xPos
= rEvtDragDrop
.getXPos() - getLeft();
250 int yPos
= rEvtDragDrop
.getYPos() - getTop();
252 CtrlGeneric
*pHitControl
= findHitControl( xPos
, yPos
);
253 if( pHitControl
&& pHitControl
->getType() == "tree" )
255 // Send a dragDrop event
256 EvtDragDrop
evt( getIntf(), xPos
, yPos
, rEvtDragDrop
.getFiles() );
257 pHitControl
->handleEvent( evt
);
261 input_thread_t
*pInput
= getIntf()->p_sys
->p_input
;
262 bool is_subtitle
= false;
263 list
<string
> files
= rEvtDragDrop
.getFiles();
264 if( files
.size() == 1 && pInput
!= NULL
)
266 list
<string
>::const_iterator it
= files
.begin();
267 char* psz_file
= make_path( it
->c_str() );
270 is_subtitle
= !input_AddSubtitleOSD( pInput
, psz_file
, true, true );
276 list
<string
>::const_iterator it
= files
.begin();
277 for( bool first
= true; it
!= files
.end(); ++it
, first
= false )
279 bool playOnDrop
= m_playOnDrop
&& first
;
280 CmdAddItem( getIntf(), it
->c_str(), playOnDrop
).execute();
284 m_pDragControl
= NULL
;
287 void TopWindow::processEvent( EvtDragOver
&rEvtDragOver
)
289 // Get the control hit by the mouse
290 int xPos
= rEvtDragOver
.getXPos() - getLeft();
291 int yPos
= rEvtDragOver
.getYPos() - getTop();
293 CtrlGeneric
*pHitControl
= findHitControl( xPos
, yPos
);
295 if( m_pDragControl
&& m_pDragControl
!= pHitControl
)
297 EvtDragLeave
evt( getIntf() );
298 m_pDragControl
->handleEvent( evt
);
301 m_pDragControl
= pHitControl
;
305 // Send a dragOver event
306 EvtDragOver
evt( getIntf(), xPos
, yPos
);
307 m_pDragControl
->handleEvent( evt
);
311 void TopWindow::processEvent( EvtDragLeave
&rEvtDragLeave
)
316 EvtDragLeave
evt( getIntf() );
317 m_pDragControl
->handleEvent( evt
);
318 m_pDragControl
= NULL
;
322 void TopWindow::forwardEvent( EvtGeneric
&rEvt
, CtrlGeneric
&rCtrl
)
324 // XXX: We should do some checks here
325 rCtrl
.handleEvent( rEvt
);
329 void TopWindow::refresh( int left
, int top
, int width
, int height
)
331 if( m_pActiveLayout
)
333 m_pActiveLayout
->getImage()->copyToWindow( *getOSWindow(), left
, top
,
334 width
, height
, left
, top
);
339 void TopWindow::setActiveLayout( GenericLayout
*pLayout
)
341 bool isVisible
= getVisibleVar().get();
342 if( m_pActiveLayout
)
346 m_pActiveLayout
->onHide();
348 // The current layout becomes inactive
349 m_pActiveLayout
->getActiveVar().set( false );
351 // if both layouts have the same original size, infer a
352 // subsequent resize of the active layout has to be applied
353 // to the new layout about to become active
354 if( pLayout
->isTightlyCoupledWith( *m_pActiveLayout
) )
355 pLayout
->resize( m_pActiveLayout
->getWidth(),
356 m_pActiveLayout
->getHeight() );
359 pLayout
->setWindow( this );
360 m_pActiveLayout
= pLayout
;
361 // Get the size of the layout and resize the window
362 resize( pLayout
->getWidth(), pLayout
->getHeight() );
369 // The new layout is active
370 pLayout
->getActiveVar().set( true );
374 const GenericLayout
& TopWindow::getActiveLayout() const
376 return *m_pActiveLayout
;
380 void TopWindow::innerShow()
382 // First, refresh the layout
383 if( m_pActiveLayout
)
385 m_pActiveLayout
->onShow();
389 GenericWindow::innerShow();
393 void TopWindow::innerHide()
395 if( m_pActiveLayout
)
397 // Notify the active layout
398 m_pActiveLayout
->onHide();
401 GenericWindow::innerHide();
405 void TopWindow::updateShape()
407 // Set the shape of the window
408 if( m_pActiveLayout
)
410 OSGraphics
*pImage
= m_pActiveLayout
->getImage();
413 pImage
->applyMaskToWindow( *getOSWindow() );
419 void TopWindow::onControlCapture( const CtrlGeneric
&rCtrl
)
421 // Set the capturing control
422 m_pCapturingControl
= (CtrlGeneric
*) &rCtrl
;
426 void TopWindow::onControlRelease( const CtrlGeneric
&rCtrl
)
428 // Release the capturing control
429 if( m_pCapturingControl
== &rCtrl
)
431 m_pCapturingControl
= NULL
;
435 msg_Dbg( getIntf(), "control had not captured the mouse" );
438 // Send an enter event to the control under the mouse, if it doesn't
439 // have received it yet
440 if( m_pLastHitControl
&& m_pLastHitControl
!= &rCtrl
)
442 EvtEnter
evt( getIntf() );
443 m_pLastHitControl
->handleEvent( evt
);
446 m_rWindowManager
.hideTooltip();
447 UString tipText
= m_pLastHitControl
->getTooltipText();
448 if( tipText
.length() > 0 )
450 // Set the tooltip text variable
451 VarManager
*pVarManager
= VarManager::instance( getIntf() );
452 pVarManager
->getTooltipText().set( tipText
);
453 m_rWindowManager
.showTooltip();
459 void TopWindow::onTooltipChange( const CtrlGeneric
&rCtrl
)
461 // Check that the control is the active one
462 if( m_pLastHitControl
&& m_pLastHitControl
== &rCtrl
)
464 if( rCtrl
.getTooltipText().size() )
466 // Set the tooltip text variable
467 VarManager
*pVarManager
= VarManager::instance( getIntf() );
468 pVarManager
->getTooltipText().set( rCtrl
.getTooltipText() );
469 m_rWindowManager
.showTooltip();
473 // Nothing to display, so hide the tooltip
474 m_rWindowManager
.hideTooltip();
480 CtrlGeneric
*TopWindow::findHitControl( int xPos
, int yPos
)
482 if( m_pActiveLayout
== NULL
)
487 // Get the controls in the active layout
488 const list
<LayeredControl
> &ctrlList
= m_pActiveLayout
->getControlList();
489 list
<LayeredControl
>::const_reverse_iterator iter
;
491 // New control hit by the mouse
492 CtrlGeneric
*pNewHitControl
= NULL
;
494 // Loop on the control list to find the uppest hit control
495 for( iter
= ctrlList
.rbegin(); iter
!= ctrlList
.rend(); ++iter
)
497 // Get the position of the control in the layout
498 const Position
*pos
= (*iter
).m_pControl
->getPosition();
501 // Compute the coordinates of the mouse relative to the control
502 int xRel
= xPos
- pos
->getLeft();
503 int yRel
= yPos
- pos
->getTop();
505 CtrlGeneric
*pCtrl
= (*iter
).m_pControl
;
507 if( pCtrl
->isVisible() && pCtrl
->mouseOver( xRel
, yRel
) )
509 pNewHitControl
= (*iter
).m_pControl
;
515 msg_Dbg( getIntf(), "control at NULL position" );
519 // If the hit control has just been entered, send it an enter event
520 if( pNewHitControl
&& (pNewHitControl
!= m_pLastHitControl
) )
522 // Don't send the event if another control captured the mouse
523 if( !m_pCapturingControl
|| (m_pCapturingControl
== pNewHitControl
) )
525 EvtEnter
evt( getIntf() );
526 pNewHitControl
->handleEvent( evt
);
528 if( !m_pCapturingControl
)
531 m_rWindowManager
.hideTooltip();
532 UString tipText
= pNewHitControl
->getTooltipText();
533 if( tipText
.length() > 0 )
535 // Set the tooltip text variable
536 VarManager
*pVarManager
= VarManager::instance( getIntf() );
537 pVarManager
->getTooltipText().set( tipText
);
538 m_rWindowManager
.showTooltip();
544 return pNewHitControl
;
549 void TopWindow::setLastHit( CtrlGeneric
*pNewHitControl
)
551 // Send a leave event to the left control
552 if( m_pLastHitControl
&& (pNewHitControl
!= m_pLastHitControl
) )
554 // Don't send the event if another control captured the mouse
555 if( !m_pCapturingControl
|| (m_pCapturingControl
== m_pLastHitControl
))
557 EvtLeave
evt( getIntf() );
558 m_pLastHitControl
->handleEvent( evt
);
562 m_pLastHitControl
= pNewHitControl
;