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 "../controls/ctrl_generic.hpp"
35 #include "../events/evt_refresh.hpp"
36 #include "../events/evt_enter.hpp"
37 #include "../events/evt_focus.hpp"
38 #include "../events/evt_leave.hpp"
39 #include "../events/evt_menu.hpp"
40 #include "../events/evt_motion.hpp"
41 #include "../events/evt_mouse.hpp"
42 #include "../events/evt_key.hpp"
43 #include "../events/evt_special.hpp"
44 #include "../events/evt_scroll.hpp"
45 #include "../utils/position.hpp"
46 #include "../utils/ustring.hpp"
51 TopWindow::TopWindow( intf_thread_t
*pIntf
, int left
, int top
,
52 WindowManager
&rWindowManager
,
53 bool dragDrop
, bool playOnDrop
, bool visible
):
54 GenericWindow( pIntf
, left
, top
, dragDrop
, playOnDrop
, NULL
),
55 m_visible( visible
), m_rWindowManager( rWindowManager
),
56 m_pActiveLayout( NULL
), m_pLastHitControl( NULL
),
57 m_pCapturingControl( NULL
), m_pFocusControl( NULL
), m_currModifier( 0 )
59 // Register as a moving window
60 m_rWindowManager
.registerWindow( *this );
62 // Create the "maximized" variable and register it in the manager
63 m_pVarMaximized
= new VarBoolImpl( pIntf
);
64 VarManager::instance( pIntf
)->registerVar( VariablePtr( m_pVarMaximized
) );
68 TopWindow::~TopWindow()
70 // Unregister from the window manager
71 m_rWindowManager
.unregisterWindow( *this );
75 void TopWindow::processEvent( EvtFocus
&rEvtFocus
)
77 // fprintf(stderr, rEvtFocus.getAsString().c_str());
81 void TopWindow::processEvent( EvtMenu
&rEvtMenu
)
83 Popup
*pPopup
= m_rWindowManager
.getActivePopup();
84 // We should never receive a menu event when there is no active popup!
87 msg_Warn( getIntf(), "unexpected menu event, ignoring" );
91 pPopup
->handleEvent( rEvtMenu
);
95 void TopWindow::processEvent( EvtMotion
&rEvtMotion
)
97 // New control hit by the mouse
98 CtrlGeneric
*pNewHitControl
=
99 findHitControl( rEvtMotion
.getXPos() - getLeft(),
100 rEvtMotion
.getYPos() - getTop() );
102 setLastHit( pNewHitControl
);
104 /// Update the help text
105 VarManager
*pVarManager
= VarManager::instance( getIntf() );
108 pVarManager
->getHelpText().set( pNewHitControl
->getHelpText() );
111 // Send a motion event to the hit control, or to the control
112 // that captured the mouse, if any
113 CtrlGeneric
*pActiveControl
= pNewHitControl
;
114 if( m_pCapturingControl
)
116 pActiveControl
= m_pCapturingControl
;
120 // Compute the coordinates relative to the window
121 int xPos
= rEvtMotion
.getXPos() - getLeft();
122 int yPos
= rEvtMotion
.getYPos() - getTop();
123 // Send a motion event
124 EvtMotion
evt( getIntf(), xPos
, yPos
);
125 pActiveControl
->handleEvent( evt
);
130 void TopWindow::processEvent( EvtLeave
&rEvtLeave
)
132 // No more hit control
135 if( !m_pCapturingControl
)
137 m_rWindowManager
.hideTooltip();
142 void TopWindow::processEvent( EvtMouse
&rEvtMouse
)
144 // Get the control hit by the mouse
145 CtrlGeneric
*pNewHitControl
= findHitControl( rEvtMouse
.getXPos(),
146 rEvtMouse
.getYPos() );
147 setLastHit( pNewHitControl
);
149 // Change the focused control
150 if( rEvtMouse
.getAction() == EvtMouse::kDown
)
153 m_rWindowManager
.raise( *this );
155 if( pNewHitControl
&& pNewHitControl
->isFocusable() )
157 // If a new control gains the focus, the previous one loses it
158 if( m_pFocusControl
&& m_pFocusControl
!= pNewHitControl
)
160 EvtFocus
evt( getIntf(), false );
161 m_pFocusControl
->handleEvent( evt
);
163 if( pNewHitControl
!= m_pFocusControl
)
165 m_pFocusControl
= pNewHitControl
;
166 EvtFocus
evt( getIntf(), true );
167 pNewHitControl
->handleEvent( evt
);
170 else if( m_pFocusControl
)
172 // The previous control loses the focus
173 EvtFocus
evt( getIntf(), false );
174 m_pFocusControl
->handleEvent( evt
);
175 m_pFocusControl
= NULL
;
179 // Send a mouse event to the hit control, or to the control
180 // that captured the mouse, if any
181 CtrlGeneric
*pActiveControl
= pNewHitControl
;
182 if( m_pCapturingControl
)
184 pActiveControl
= m_pCapturingControl
;
188 pActiveControl
->handleEvent( rEvtMouse
);
193 void TopWindow::processEvent( EvtKey
&rEvtKey
)
195 // Forward the event to the focused control, if any
196 if( m_pFocusControl
)
198 m_pFocusControl
->handleEvent( rEvtKey
);
202 // Only do the action when the key is down
203 if( rEvtKey
.getKeyState() == EvtKey::kDown
)
205 //XXX not to be hardcoded!
206 // Ctrl-S = Change skin
207 if( (rEvtKey
.getMod() & EvtInput::kModCtrl
) &&
208 rEvtKey
.getKey() == 's' )
210 CmdDlgChangeSkin
cmd( getIntf() );
215 //XXX not to be hardcoded!
216 // Ctrl-T = Toggle on top
217 if( (rEvtKey
.getMod() & EvtInput::kModCtrl
) &&
218 rEvtKey
.getKey() == 't' )
220 CmdOnTop
cmd( getIntf() );
225 var_SetInteger( getIntf()->p_libvlc
, "key-pressed",
226 rEvtKey
.getModKey() );
229 // Always store the modifier, which can be needed for scroll events.
230 m_currModifier
= rEvtKey
.getMod();
233 void TopWindow::processEvent( EvtScroll
&rEvtScroll
)
238 // Get the control hit by the mouse
239 CtrlGeneric
*pNewHitControl
= findHitControl( rEvtScroll
.getXPos(),
240 rEvtScroll
.getYPos());
241 setLastHit( pNewHitControl
);
243 // Send a mouse event to the hit control, or to the control
244 // that captured the mouse, if any
245 CtrlGeneric
*pActiveControl
= pNewHitControl
;
247 if( m_pCapturingControl
)
249 pActiveControl
= m_pCapturingControl
;
253 pActiveControl
->handleEvent( rEvtScroll
);
257 // Treat the scroll event as a hotkey plus current modifiers
258 int i
= (rEvtScroll
.getDirection() == EvtScroll::kUp
?
259 KEY_MOUSEWHEELUP
: KEY_MOUSEWHEELDOWN
) | m_currModifier
;
261 var_SetInteger( getIntf()->p_libvlc
, "key-pressed", i
);
266 void TopWindow::forwardEvent( EvtGeneric
&rEvt
, CtrlGeneric
&rCtrl
)
268 // XXX: We should do some checks here
269 rCtrl
.handleEvent( rEvt
);
273 void TopWindow::refresh( int left
, int top
, int width
, int height
)
275 if( m_pActiveLayout
)
277 m_pActiveLayout
->getImage()->copyToWindow( *getOSWindow(), left
, top
,
278 width
, height
, left
, top
);
283 void TopWindow::setActiveLayout( GenericLayout
*pLayout
)
285 bool isVisible
= getVisibleVar().get();
286 if( m_pActiveLayout
)
290 m_pActiveLayout
->onHide();
292 // The current layout becomes inactive
293 m_pActiveLayout
->getActiveVar().set( false );
296 pLayout
->setWindow( this );
297 m_pActiveLayout
= pLayout
;
298 // Get the size of the layout and resize the window
299 resize( pLayout
->getWidth(), pLayout
->getHeight() );
306 // The new layout is active
307 pLayout
->getActiveVar().set( true );
311 const GenericLayout
& TopWindow::getActiveLayout() const
313 return *m_pActiveLayout
;
317 void TopWindow::innerShow()
319 // First, refresh the layout
320 if( m_pActiveLayout
)
322 m_pActiveLayout
->onShow();
326 GenericWindow::innerShow();
328 // place the top window on the screen (after show!)
329 move( getLeft(), getTop() );
333 void TopWindow::innerHide()
335 if( m_pActiveLayout
)
337 // Notify the active layout
338 m_pActiveLayout
->onHide();
341 GenericWindow::innerHide();
345 void TopWindow::updateShape()
347 // Set the shape of the window
348 if( m_pActiveLayout
)
350 OSGraphics
*pImage
= m_pActiveLayout
->getImage();
353 pImage
->applyMaskToWindow( *getOSWindow() );
359 void TopWindow::onControlCapture( const CtrlGeneric
&rCtrl
)
361 // Set the capturing control
362 m_pCapturingControl
= (CtrlGeneric
*) &rCtrl
;
366 void TopWindow::onControlRelease( const CtrlGeneric
&rCtrl
)
368 // Release the capturing control
369 if( m_pCapturingControl
== &rCtrl
)
371 m_pCapturingControl
= NULL
;
375 msg_Dbg( getIntf(), "control had not captured the mouse" );
378 // Send an enter event to the control under the mouse, if it doesn't
379 // have received it yet
380 if( m_pLastHitControl
&& m_pLastHitControl
!= &rCtrl
)
382 EvtEnter
evt( getIntf() );
383 m_pLastHitControl
->handleEvent( evt
);
386 m_rWindowManager
.hideTooltip();
387 UString tipText
= m_pLastHitControl
->getTooltipText();
388 if( tipText
.length() > 0 )
390 // Set the tooltip text variable
391 VarManager
*pVarManager
= VarManager::instance( getIntf() );
392 pVarManager
->getTooltipText().set( tipText
);
393 m_rWindowManager
.showTooltip();
399 void TopWindow::onTooltipChange( const CtrlGeneric
&rCtrl
)
401 // Check that the control is the active one
402 if( m_pLastHitControl
&& m_pLastHitControl
== &rCtrl
)
404 if( rCtrl
.getTooltipText().size() )
406 // Set the tooltip text variable
407 VarManager
*pVarManager
= VarManager::instance( getIntf() );
408 pVarManager
->getTooltipText().set( rCtrl
.getTooltipText() );
409 m_rWindowManager
.showTooltip();
413 // Nothing to display, so hide the tooltip
414 m_rWindowManager
.hideTooltip();
420 CtrlGeneric
*TopWindow::findHitControl( int xPos
, int yPos
)
422 if( m_pActiveLayout
== NULL
)
427 // Get the controls in the active layout
428 const list
<LayeredControl
> &ctrlList
= m_pActiveLayout
->getControlList();
429 list
<LayeredControl
>::const_reverse_iterator iter
;
431 // New control hit by the mouse
432 CtrlGeneric
*pNewHitControl
= NULL
;
434 // Loop on the control list to find the uppest hit control
435 for( iter
= ctrlList
.rbegin(); iter
!= ctrlList
.rend(); iter
++ )
437 // Get the position of the control in the layout
438 const Position
*pos
= (*iter
).m_pControl
->getPosition();
441 // Compute the coordinates of the mouse relative to the control
442 int xRel
= xPos
- pos
->getLeft();
443 int yRel
= yPos
- pos
->getTop();
445 CtrlGeneric
*pCtrl
= (*iter
).m_pControl
;
447 if( pCtrl
->isVisible() && pCtrl
->mouseOver( xRel
, yRel
) )
449 pNewHitControl
= (*iter
).m_pControl
;
455 msg_Dbg( getIntf(), "control at NULL position" );
459 // If the hit control has just been entered, send it an enter event
460 if( pNewHitControl
&& (pNewHitControl
!= m_pLastHitControl
) )
462 // Don't send the event if another control captured the mouse
463 if( !m_pCapturingControl
|| (m_pCapturingControl
== pNewHitControl
) )
465 EvtEnter
evt( getIntf() );
466 pNewHitControl
->handleEvent( evt
);
468 if( !m_pCapturingControl
)
471 m_rWindowManager
.hideTooltip();
472 UString tipText
= pNewHitControl
->getTooltipText();
473 if( tipText
.length() > 0 )
475 // Set the tooltip text variable
476 VarManager
*pVarManager
= VarManager::instance( getIntf() );
477 pVarManager
->getTooltipText().set( tipText
);
478 m_rWindowManager
.showTooltip();
484 return pNewHitControl
;
489 void TopWindow::setLastHit( CtrlGeneric
*pNewHitControl
)
491 // Send a leave event to the left control
492 if( m_pLastHitControl
&& (pNewHitControl
!= m_pLastHitControl
) )
494 // Don't send the event if another control captured the mouse
495 if( !m_pCapturingControl
|| (m_pCapturingControl
== m_pLastHitControl
))
497 EvtLeave
evt( getIntf() );
498 m_pLastHitControl
->handleEvent( evt
);
502 m_pLastHitControl
= pNewHitControl
;