1 /*****************************************************************************
2 * main_interface.cpp : Main interface
3 ****************************************************************************
4 * Copyright (C) 2006-2011 VideoLAN and AUTHORS
7 * Authors: Clément Stenac <zorglub@videolan.org>
8 * Jean-Baptiste Kempf <jb@videolan.org>
9 * Ilkka Ollakka <ileoo@videolan.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
32 #include "main_interface.hpp"
33 #include "input_manager.hpp" // Creation
34 #include "actions_manager.hpp" // killInstance
36 #include "util/customwidgets.hpp" // qtEventToVLCKey, QVLCStackedWidget
37 #include "util/qt_dirs.hpp" // toNativeSeparators
38 #include "util/imagehelper.hpp"
40 #include "components/interface_widgets.hpp" // bgWidget, videoWidget
41 #include "components/controller.hpp" // controllers
42 #include "components/playlist/playlist.hpp" // plWidget
43 #include "dialogs/firstrun.hpp" // First Run
44 #include "dialogs/playlist.hpp" // PlaylistDialog
46 #include "menus.hpp" // Menu creation
47 #include "recents.hpp" // RecentItems when DnD
49 #include <QCloseEvent>
62 #include <QStackedWidget>
68 #if ! HAS_QT510 && defined(QT5_HAS_X11)
70 # include <X11/Xlib.h>
75 #include <vlc_actions.h> /* Wheel event */
76 #include <vlc_vout_display.h> /* vout_thread_t and VOUT_ events */
80 /* Callback prototypes */
81 static int PopupMenuCB( vlc_object_t
*p_this
, const char *psz_variable
,
82 vlc_value_t old_val
, vlc_value_t new_val
, void *param
);
83 static int IntfShowCB( vlc_object_t
*p_this
, const char *psz_variable
,
84 vlc_value_t old_val
, vlc_value_t new_val
, void *param
);
85 static int IntfBossCB( vlc_object_t
*p_this
, const char *psz_variable
,
86 vlc_value_t old_val
, vlc_value_t new_val
, void *param
);
87 static int IntfRaiseMainCB( vlc_object_t
*p_this
, const char *psz_variable
,
88 vlc_value_t old_val
, vlc_value_t new_val
,
91 const QEvent::Type
MainInterface::ToolbarsNeedRebuild
=
92 (QEvent::Type
)QEvent::registerEventType();
94 MainInterface::MainInterface( intf_thread_t
*_p_intf
) : QVLCMW( _p_intf
)
96 /* Variables initialisation */
99 playlistWidget
= NULL
;
100 stackCentralOldWidget
= NULL
;
101 lastWinScreen
= NULL
;
103 fullscreenControls
= NULL
;
108 b_hideAfterCreation
= false; // --qt-start-minimized
109 playlistVisible
= false;
111 b_interfaceFullScreen
= false;
112 b_hasPausedWhenMinimized
= false;
114 b_maximizedView
= false;
115 b_isWindowTiled
= false;
117 /* Ask for Privacy */
118 FirstRun::CheckAndRun( this, p_intf
);
121 * Configuration and settings
122 * Pre-building of interface
125 setFocusPolicy( Qt::StrongFocus
);
126 setAcceptDrops( true );
127 setWindowRole( "vlc-main" );
128 setWindowIcon( QApplication::windowIcon() );
129 setWindowOpacity( var_InheritFloat( p_intf
, "qt-opacity" ) );
131 /* Does the interface resize to video size or the opposite */
132 b_autoresize
= var_InheritBool( p_intf
, "qt-video-autoresize" );
134 /* Are we in the enhanced always-video mode or not ? */
135 b_minimalView
= var_InheritBool( p_intf
, "qt-minimal-view" );
137 /* Do we want anoying popups or not */
138 i_notificationSetting
= var_InheritInteger( p_intf
, "qt-notification" );
141 b_pauseOnMinimize
= var_InheritBool( p_intf
, "qt-pause-minimized" );
143 /* Set the other interface settings */
144 settings
= getSettings();
147 b_plDocked
= getSettings()->value( "MainWindow/pl-dock-status", true ).toBool();
149 /* Should the UI stays on top of other windows */
150 b_interfaceOnTop
= var_InheritBool( p_intf
, "video-on-top" );
152 #ifdef QT5_HAS_WAYLAND
153 b_hasWayland
= QGuiApplication::platformName()
154 .startsWith(QLatin1String("wayland"), Qt::CaseInsensitive
);
157 /**************************
158 * UI and Widgets design
159 **************************/
160 setVLCWindowsTitle();
165 VLCMenuBar::createMenuBar( this, p_intf
);
166 CONNECT( THEMIM
->getIM(), voutListChanged( vout_thread_t
**, int ),
167 THEDP
, destroyPopupMenu() );
169 createMainWidget( settings
);
175 setStatusBarVisibility( getSettings()->value( "MainWindow/status-bar-visible", false ).toBool() );
177 /*********************************
178 * Create the Systray Management *
179 *********************************/
182 /*************************************************************
183 * Connect the input manager to the GUI elements it manages *
184 * Beware initSystray did some connects on input manager too *
185 *************************************************************/
187 * Connects on nameChanged()
188 * Those connects are different because options can impeach them to trigger.
190 /* Main Interface statusbar */
191 CONNECT( THEMIM
->getIM(), nameChanged( const QString
& ),
192 this, setName( const QString
& ) );
193 /* and title of the Main Interface*/
194 if( var_InheritBool( p_intf
, "qt-name-in-title" ) )
196 CONNECT( THEMIM
->getIM(), nameChanged( const QString
& ),
197 this, setVLCWindowsTitle( const QString
& ) );
199 CONNECT( THEMIM
, inputChanged( bool ), this, onInputChanged( bool ) );
201 /* END CONNECTS ON IM */
203 /* VideoWidget connects for asynchronous calls */
204 b_videoFullScreen
= false;
205 connect( this, SIGNAL(askGetVideo(struct vout_window_t
*, unsigned, unsigned, bool, bool*)),
206 this, SLOT(getVideoSlot(struct vout_window_t
*, unsigned, unsigned, bool, bool*)),
207 Qt::BlockingQueuedConnection
);
208 connect( this, SIGNAL(askReleaseVideo( void )),
209 this, SLOT(releaseVideoSlot( void )),
210 Qt::BlockingQueuedConnection
);
211 CONNECT( this, askVideoOnTop(bool), this, setVideoOnTop(bool));
217 CONNECT( videoWidget
, sizeChanged( int, int ),
218 this, videoSizeChanged( int, int ) );
220 CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
221 this, setVideoSize( unsigned int, unsigned int ) );
223 CONNECT( this, askVideoSetFullScreen( bool ),
224 this, setVideoFullScreen( bool ) );
225 CONNECT( this, askHideMouse( bool ),
226 this, setHideMouse( bool ) );
229 CONNECT( THEDP
, toolBarConfUpdated(), this, toolBarConfUpdated() );
230 installEventFilter( this );
232 CONNECT( this, askToQuit(), THEDP
, quit() );
234 CONNECT( this, askBoss(), this, setBoss() );
235 CONNECT( this, askRaise(), this, setRaise() );
238 connect( THEDP
, &DialogsProvider::releaseMouseEvents
, this, &MainInterface::voutReleaseMouseEvents
) ;
239 /** END of CONNECTS**/
245 var_AddCallback( p_intf
->obj
.libvlc
, "intf-toggle-fscontrol", IntfShowCB
, p_intf
);
246 var_AddCallback( p_intf
->obj
.libvlc
, "intf-boss", IntfBossCB
, p_intf
);
247 var_AddCallback( p_intf
->obj
.libvlc
, "intf-show", IntfRaiseMainCB
, p_intf
);
249 /* Register callback for the intf-popupmenu variable */
250 var_AddCallback( p_intf
->obj
.libvlc
, "intf-popupmenu", PopupMenuCB
, p_intf
);
253 /* Final Sizing, restoration and placement of the interface */
254 if( settings
->value( "MainWindow/playlist-visible", false ).toBool() )
257 QVLCTools::restoreWidgetPosition( settings
, this, QSize(600, 420) );
259 b_interfaceFullScreen
= isFullScreen();
261 setVisible( !b_hideAfterCreation
);
263 /* Switch to minimal view if needed, must be called after the show() */
265 toggleMinimalView( true );
267 computeMinimumSize();
270 MainInterface::~MainInterface()
272 /* Unsure we hide the videoWidget before destroying it */
273 if( stackCentralOldWidget
== videoWidget
)
279 /* Be sure to kill the actionsManager... Only used in the MI and control */
280 ActionsManager::killInstance();
282 /* Delete the FSC controller */
283 delete fullscreenControls
;
287 settings
->beginGroup("MainWindow");
288 settings
->setValue( "pl-dock-status", b_plDocked
);
290 /* Save playlist state */
291 settings
->setValue( "playlist-visible", playlistVisible
);
293 settings
->setValue( "adv-controls",
294 getControlsVisibilityStatus() & CONTROLS_ADVANCED
);
295 settings
->setValue( "status-bar-visible", b_statusbarVisible
);
297 /* Save the stackCentralW sizes */
298 settings
->setValue( "bgSize", stackWidgetsSizes
[bgWidget
] );
299 settings
->setValue( "playlistSize", stackWidgetsSizes
[playlistWidget
] );
300 settings
->endGroup();
303 QVLCTools::saveWidgetPosition(settings
, this);
305 /* Unregister callbacks */
306 var_DelCallback( p_intf
->obj
.libvlc
, "intf-boss", IntfBossCB
, p_intf
);
307 var_DelCallback( p_intf
->obj
.libvlc
, "intf-show", IntfRaiseMainCB
, p_intf
);
308 var_DelCallback( p_intf
->obj
.libvlc
, "intf-toggle-fscontrol", IntfShowCB
, p_intf
);
309 var_DelCallback( p_intf
->obj
.libvlc
, "intf-popupmenu", PopupMenuCB
, p_intf
);
311 p_intf
->p_sys
->p_mi
= NULL
;
314 void MainInterface::computeMinimumSize()
317 if( menuBar()->isVisible() )
318 minWidth
+= controls
->sizeHint().width();
320 setMinimumWidth( minWidth
);
323 /*****************************
325 *****************************/
326 void MainInterface::recreateToolbars()
328 bool b_adv
= getControlsVisibilityStatus() & CONTROLS_ADVANCED
;
333 controls
= new ControlsWidget( p_intf
, b_adv
, this );
334 inputC
= new InputControlsWidget( p_intf
, this );
335 mainLayout
->insertWidget( 2, inputC
);
336 mainLayout
->insertWidget( settings
->value( "MainWindow/ToolbarPos", false ).toBool() ? 0: 3,
339 if( fullscreenControls
)
341 delete fullscreenControls
;
342 fullscreenControls
= new FullscreenControllerWidget( p_intf
, this );
343 CONNECT( fullscreenControls
, keyPressed( QKeyEvent
* ),
344 this, handleKeyPress( QKeyEvent
* ) );
345 THEMIM
->requestVoutUpdate();
348 setMinimalView( b_minimalView
);
351 void MainInterface::reloadPrefs()
353 i_notificationSetting
= var_InheritInteger( p_intf
, "qt-notification" );
354 b_pauseOnMinimize
= var_InheritBool( p_intf
, "qt-pause-minimized" );
355 if( !var_InheritBool( p_intf
, "qt-fs-controller" ) && fullscreenControls
)
357 delete fullscreenControls
;
358 fullscreenControls
= NULL
;
362 void MainInterface::createResumePanel( QWidget
*w
)
364 resumePanel
= new QWidget( w
);
366 QHBoxLayout
*resumePanelLayout
= new QHBoxLayout( resumePanel
);
367 resumePanelLayout
->setSpacing( 0 ); resumePanelLayout
->setMargin( 0 );
369 QLabel
*continuePixmapLabel
= new QLabel();
370 continuePixmapLabel
->setPixmap( ImageHelper::loadSvgToPixmap( ":/menu/help.svg" , fontMetrics().height(), fontMetrics().height()) );
371 continuePixmapLabel
->setContentsMargins( 5, 0, 5, 0 );
373 QLabel
*continueLabel
= new QLabel( qtr( "Do you want to restart the playback where left off?") );
375 QToolButton
*cancel
= new QToolButton( resumePanel
);
376 cancel
->setAutoRaise( true );
377 cancel
->setText( "X" );
379 QPushButton
*ok
= new QPushButton( qtr( "&Continue" ) );
381 resumePanelLayout
->addWidget( continuePixmapLabel
);
382 resumePanelLayout
->addWidget( continueLabel
);
383 resumePanelLayout
->addStretch( 1 );
384 resumePanelLayout
->addWidget( ok
);
385 resumePanelLayout
->addWidget( cancel
);
387 resumeTimer
= new QTimer( resumePanel
);
388 resumeTimer
->setSingleShot( true );
389 resumeTimer
->setInterval( 6000 );
391 CONNECT( resumeTimer
, timeout(), this, hideResumePanel() );
392 CONNECT( cancel
, clicked(), this, hideResumePanel() );
393 CONNECT( THEMIM
->getIM(), resumePlayback(int64_t), this, showResumePanel(int64_t) );
394 BUTTONACT( ok
, resumePlayback() );
396 w
->layout()->addWidget( resumePanel
);
399 void MainInterface::showResumePanel( int64_t _time
) {
400 int setting
= var_InheritInteger( p_intf
, "qt-continue" );
405 i_resumeTime
= _time
;
411 if( !isFullScreen() && !isMaximized() && !b_isWindowTiled
)
412 resizeWindow( width(), height() + resumePanel
->height() );
413 resumePanel
->setVisible(true);
414 resumeTimer
->start();
418 void MainInterface::hideResumePanel()
420 if( resumePanel
->isVisible() )
422 if( !isFullScreen() && !isMaximized() && !b_isWindowTiled
)
423 resizeWindow( width(), height() - resumePanel
->height() );
429 void MainInterface::resumePlayback()
431 if( THEMIM
->getIM()->hasInput() ) {
432 var_SetInteger( THEMIM
->getInput(), "time", i_resumeTime
);
437 void MainInterface::onInputChanged( bool hasInput
)
439 if( hasInput
== false )
441 int autoRaise
= var_InheritInteger( p_intf
, "qt-auto-raise" );
442 if ( autoRaise
== MainInterface::RAISE_NEVER
)
444 if( THEMIM
->getIM()->hasVideo() == true )
446 if( ( autoRaise
& MainInterface::RAISE_VIDEO
) == 0 )
449 else if ( ( autoRaise
& MainInterface::RAISE_AUDIO
) == 0 )
454 void MainInterface::createMainWidget( QSettings
*creationSettings
)
456 /* Create the main Widget and the mainLayout */
457 QWidget
*main
= new QWidget
;
458 setCentralWidget( main
);
459 mainLayout
= new QVBoxLayout( main
);
460 main
->setContentsMargins( 0, 0, 0, 0 );
461 mainLayout
->setSpacing( 0 ); mainLayout
->setMargin( 0 );
463 createResumePanel( main
);
465 stackCentralW
= new QVLCStackedWidget( main
);
468 if ( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY
469 && var_InheritBool( p_intf
, "qt-icon-change" ) )
471 bgWidget
= new EasterEggBackgroundWidget( p_intf
);
472 CONNECT( this, kc_pressed(), bgWidget
, animate() );
475 bgWidget
= new BackgroundWidget( p_intf
);
477 stackCentralW
->addWidget( bgWidget
);
478 if ( !var_InheritBool( p_intf
, "qt-bgcone" ) )
479 bgWidget
->setWithArt( false );
481 if ( var_InheritBool( p_intf
, "qt-bgcone-expands" ) )
482 bgWidget
->setExpandstoHeight( true );
484 /* And video Outputs */
485 if( var_InheritBool( p_intf
, "embedded-video" ) )
487 videoWidget
= new VideoWidget( p_intf
, stackCentralW
);
488 stackCentralW
->addWidget( videoWidget
);
490 mainLayout
->insertWidget( 1, stackCentralW
);
492 stackWidgetsSizes
[bgWidget
] =
493 creationSettings
->value( "MainWindow/bgSize", QSize( 600, 0 ) ).toSize();
494 /* Resize even if no-auto-resize, because we are at creation */
495 resizeStack( stackWidgetsSizes
[bgWidget
].width(), stackWidgetsSizes
[bgWidget
].height() );
497 /* Create the CONTROLS Widget */
498 controls
= new ControlsWidget( p_intf
,
499 creationSettings
->value( "MainWindow/adv-controls", false ).toBool(), this );
500 inputC
= new InputControlsWidget( p_intf
, this );
502 mainLayout
->insertWidget( 2, inputC
);
503 mainLayout
->insertWidget(
504 creationSettings
->value( "MainWindow/ToolbarPos", false ).toBool() ? 0: 3,
507 /* Visualisation, disabled for now, they SUCK */
509 visualSelector
= new VisualSelector( p_intf
);
510 mainLayout
->insertWidget( 0, visualSelector
);
511 visualSelector
->hide();
515 /* Enable the popup menu in the MI */
516 main
->setContextMenuPolicy( Qt::CustomContextMenu
);
517 CONNECT( main
, customContextMenuRequested( const QPoint
& ),
518 THEDP
, setPopupMenu() );
520 if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
521 /* Create the FULLSCREEN CONTROLS Widget */
522 if( var_InheritBool( p_intf
, "qt-fs-controller" ) )
524 fullscreenControls
= new FullscreenControllerWidget( p_intf
, this );
525 CONNECT( fullscreenControls
, keyPressed( QKeyEvent
* ),
526 this, handleKeyPress( QKeyEvent
* ) );
529 if ( b_interfaceOnTop
)
530 setWindowFlags( windowFlags() | Qt::WindowStaysOnTopHint
);
533 inline void MainInterface::initSystray()
535 bool b_systrayAvailable
= QSystemTrayIcon::isSystemTrayAvailable();
536 bool b_systrayWanted
= var_InheritBool( p_intf
, "qt-system-tray" );
538 if( var_InheritBool( p_intf
, "qt-start-minimized") )
540 if( b_systrayAvailable
)
542 b_systrayWanted
= true;
543 b_hideAfterCreation
= true;
546 msg_Err( p_intf
, "cannot start minimized without system tray bar" );
549 if( b_systrayAvailable
&& b_systrayWanted
)
553 inline void MainInterface::createStatusBar()
558 /* Widgets Creation*/
559 QStatusBar
*statusBarr
= statusBar();
561 TimeLabel
*timeLabel
= new TimeLabel( p_intf
);
562 nameLabel
= new ClickableQLabel();
563 nameLabel
->setTextInteractionFlags( Qt::TextSelectableByMouse
564 | Qt::TextSelectableByKeyboard
);
565 SpeedLabel
*speedLabel
= new SpeedLabel( p_intf
, this );
567 /* Styling those labels */
568 timeLabel
->setFrameStyle( QFrame::Sunken
| QFrame::Panel
);
569 speedLabel
->setFrameStyle( QFrame::Sunken
| QFrame::Panel
);
570 nameLabel
->setFrameStyle( QFrame::Sunken
| QFrame::StyledPanel
);
571 timeLabel
->setStyleSheet(
572 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
573 speedLabel
->setStyleSheet(
574 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
575 /* pad both label and its tooltip */
576 nameLabel
->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
578 /* and adding those */
579 statusBarr
->addWidget( nameLabel
, 8 );
580 statusBarr
->addPermanentWidget( speedLabel
, 0 );
581 statusBarr
->addPermanentWidget( timeLabel
, 0 );
583 CONNECT( nameLabel
, doubleClicked(), THEDP
, epgDialog() );
584 /* timeLabel behaviour:
585 - double clicking opens the goto time dialog
586 - right-clicking and clicking just toggle between remaining and
588 CONNECT( timeLabel
, doubleClicked(), THEDP
, gotoTimeDialog() );
590 CONNECT( THEMIM
->getIM(), encryptionChanged( bool ),
591 this, showCryptedLabel( bool ) );
593 CONNECT( THEMIM
->getIM(), seekRequested( float ),
594 timeLabel
, setDisplayPosition( float ) );
596 /* This shouldn't be necessary, but for somehow reason, the statusBarr
597 starts at height of 20px and when a text is shown it needs more space.
598 But, as the QMainWindow policy doesn't allow statusBar to change QMW's
599 geometry, we need to force a height. If you have a better idea, please
602 statusBarr
->setFixedHeight( statusBarr
->sizeHint().height() + 2 );
605 /**********************************************************************
606 * Handling of sizing of the components
607 **********************************************************************/
609 void MainInterface::debug()
613 msg_Dbg( p_intf
, "Controls size: %i - %i", controls
->size().height(), controls
->size().width() );
614 msg_Dbg( p_intf
, "Controls minimumsize: %i - %i", controls
->minimumSize().height(), controls
->minimumSize().width() );
615 msg_Dbg( p_intf
, "Controls sizeHint: %i - %i", controls
->sizeHint().height(), controls
->sizeHint().width() );
618 msg_Dbg( p_intf
, "size: %i - %i", size().height(), size().width() );
619 msg_Dbg( p_intf
, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
620 msg_Dbg( p_intf
, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
622 msg_Dbg( p_intf
, "Stack size: %i - %i", stackCentralW
->size().height(), stackCentralW
->size().width() );
623 msg_Dbg( p_intf
, "Stack sizeHint: %i - %i", stackCentralW
->sizeHint().height(), stackCentralW
->sizeHint().width() );
624 msg_Dbg( p_intf
, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
628 inline void MainInterface::showVideo() { showTab( videoWidget
); }
629 inline void MainInterface::restoreStackOldWidget()
630 { showTab( stackCentralOldWidget
); }
632 inline void MainInterface::showTab( QWidget
*widget
)
634 if ( !widget
) widget
= bgWidget
; /* trying to restore a null oldwidget */
636 if ( stackCentralOldWidget
)
637 msg_Dbg( p_intf
, "Old stackCentralOldWidget %s at index %i",
638 stackCentralOldWidget
->metaObject()->className(),
639 stackCentralW
->indexOf( stackCentralOldWidget
) );
640 msg_Dbg( p_intf
, "ShowTab request for %s", widget
->metaObject()->className() );
642 if ( stackCentralW
->currentWidget() == widget
)
645 /* fixing when the playlist has been undocked after being hidden.
646 restoreStackOldWidget() is called when video stops but
647 stackCentralOldWidget would still be pointing to playlist */
648 if ( widget
== playlistWidget
&& !isPlDocked() )
651 stackCentralOldWidget
= stackCentralW
->currentWidget();
652 stackWidgetsSizes
[stackCentralOldWidget
] = stackCentralW
->size();
654 /* If we are playing video, embedded */
655 if( videoWidget
&& THEMIM
->getIM()->hasVideo() )
657 /* Video -> Playlist */
658 if( videoWidget
== stackCentralOldWidget
&& widget
== playlistWidget
)
660 stackCentralW
->removeWidget( videoWidget
);
661 videoWidget
->show(); videoWidget
->raise();
664 /* Playlist -> Video */
665 if( playlistWidget
== stackCentralOldWidget
&& widget
== videoWidget
)
667 playlistWidget
->artContainer
->removeWidget( videoWidget
);
668 videoWidget
->show(); videoWidget
->raise();
669 stackCentralW
->addWidget( videoWidget
);
672 /* Embedded playlist -> Non-embedded playlist */
673 if( bgWidget
== stackCentralOldWidget
&& widget
== videoWidget
)
675 /* In rare case when video is started before the interface */
676 if( playlistWidget
!= NULL
)
677 playlistWidget
->artContainer
->removeWidget( videoWidget
);
678 videoWidget
->show(); videoWidget
->raise();
679 stackCentralW
->addWidget( videoWidget
);
680 stackCentralW
->setCurrentWidget( videoWidget
);
684 stackCentralW
->setCurrentWidget( widget
);
686 resizeStack( stackWidgetsSizes
[widget
].width(), stackWidgetsSizes
[widget
].height() );
689 msg_Dbg( p_intf
, "Stack state changed to %s, index %i",
690 stackCentralW
->currentWidget()->metaObject()->className(),
691 stackCentralW
->currentIndex() );
692 msg_Dbg( p_intf
, "New stackCentralOldWidget %s at index %i",
693 stackCentralOldWidget
->metaObject()->className(),
694 stackCentralW
->indexOf( stackCentralOldWidget
) );
697 /* This part is done later, to account for the new pl size */
698 if( videoWidget
&& THEMIM
->getIM()->hasVideo() &&
699 videoWidget
== stackCentralOldWidget
&& widget
== playlistWidget
)
701 playlistWidget
->artContainer
->addWidget( videoWidget
);
702 playlistWidget
->artContainer
->setCurrentWidget( videoWidget
);
706 void MainInterface::toggleFSC()
708 if( !fullscreenControls
) return;
710 IMEvent
*eShow
= new IMEvent( IMEvent::FullscreenControlToggle
);
711 QApplication::postEvent( fullscreenControls
, eShow
);
714 /****************************************************************************
716 ****************************************************************************/
720 * You must not change the state of this object or other Qt UI objects,
721 * from the video output thread - only from the Qt UI main loop thread.
722 * All window provider queries must be handled through signals or events.
723 * That's why we have all those emit statements...
725 bool MainInterface::getVideo( struct vout_window_t
*p_wnd
,
726 unsigned int i_width
, unsigned int i_height
,
731 /* This is a blocking call signal. Results are stored directly in the
732 * vout_window_t and boolean pointers. Beware of deadlocks! */
733 emit
askGetVideo( p_wnd
, i_width
, i_height
, fullscreen
, &result
);
737 void MainInterface::getVideoSlot( struct vout_window_t
*p_wnd
,
738 unsigned i_width
, unsigned i_height
,
739 bool fullscreen
, bool *res
)
741 /* Hidden or minimized, activate */
742 if( isHidden() || isMinimized() )
743 toggleUpdateSystrayMenu();
745 /* Request the videoWidget */
748 videoWidget
= new VideoWidget( p_intf
, stackCentralW
);
749 stackCentralW
->addWidget( videoWidget
);
751 *res
= videoWidget
->request( p_wnd
);
752 if( *res
) /* The videoWidget is available */
754 setVideoFullScreen( fullscreen
);
756 /* Consider the video active now */
759 /* Ask videoWidget to resize correctly, if we are in normal mode */
762 qreal factor
= videoWidget
->devicePixelRatioF();
764 i_width
= qRound( (qreal
) i_width
/ factor
);
765 i_height
= qRound( (qreal
) i_height
/ factor
);
768 videoWidget
->setSize( i_width
, i_height
);
773 /* Asynchronous call from the WindowClose function */
774 void MainInterface::releaseVideo( void )
776 emit
askReleaseVideo();
779 /* Function that is CONNECTED to the previous emit */
780 void MainInterface::releaseVideoSlot( void )
782 /* This function is called when the embedded video window is destroyed,
783 * or in the rare case that the embedded window is still here but the
784 * Qt interface exits. */
785 assert( videoWidget
);
786 videoWidget
->release();
787 setVideoOnTop( false );
788 setVideoFullScreen( false );
791 if( stackCentralW
->currentWidget() == videoWidget
)
792 restoreStackOldWidget();
793 else if( playlistWidget
&&
794 playlistWidget
->artContainer
->currentWidget() == videoWidget
)
796 playlistWidget
->artContainer
->setCurrentIndex( 0 );
797 stackCentralW
->addWidget( videoWidget
);
800 /* We don't want to have a blank video to popup */
801 stackCentralOldWidget
= bgWidget
;
804 // The provided size is in physical pixels, coming from the core.
805 void MainInterface::setVideoSize( unsigned int w
, unsigned int h
)
807 if (!isFullScreen() && !isMaximized() )
809 /* Resize video widget to video size, or keep it at the same
810 * size. Call setSize() either way so that vout_window_ReportSize
811 * will always get called.
812 * If the video size is too large for the screen, resize it
813 * to the screen size.
817 QRect screen
= QApplication::desktop()->availableGeometry();
819 float factor
= videoWidget
->devicePixelRatioF();
823 if( (float)h
/ factor
> screen
.height() )
829 if( menuBar()->isVisible() )
830 h
-= menuBar()->height();
831 if( controls
->isVisible() )
832 h
-= controls
->height();
833 if( statusBar()->isVisible() )
834 h
-= statusBar()->height();
835 if( inputC
->isVisible() )
836 h
-= inputC
->height();
838 h
-= style()->pixelMetric(QStyle::PM_TitleBarHeight
);
839 h
-= style()->pixelMetric(QStyle::PM_LayoutBottomMargin
);
840 h
-= 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth
);
844 // Convert the size in logical pixels
845 w
= qRound( (float)w
/ factor
);
846 h
= qRound( (float)h
/ factor
);
847 msg_Dbg( p_intf
, "Logical video size: %ux%u", w
, h
);
849 videoWidget
->setSize( w
, h
);
852 videoWidget
->setSize( videoWidget
->width(), videoWidget
->height() );
856 void MainInterface::videoSizeChanged( int w
, int h
)
858 if( !playlistWidget
|| playlistWidget
->artContainer
->currentWidget() != videoWidget
)
862 void MainInterface::setVideoFullScreen( bool fs
)
864 b_videoFullScreen
= fs
;
867 int numscreen
= var_InheritInteger( p_intf
, "qt-fullscreen-screennumber" );
868 /* if user hasn't defined screennumber, or screennumber that is bigger
869 * than current number of screens, take screennumber where current interface
872 if( numscreen
< 0 || numscreen
>= QApplication::desktop()->screenCount() )
873 numscreen
= QApplication::desktop()->screenNumber( p_intf
->p_sys
->p_mi
);
875 if( fullscreenControls
)
876 fullscreenControls
->setTargetScreen( numscreen
);
878 if ( numscreen
>= 0 )
881 QRect screenres
= QApplication::desktop()->screenGeometry( numscreen
);
882 lastWinScreen
= windowHandle()->screen();
883 #ifdef QT5_HAS_WAYLAND
885 windowHandle()->setScreen(QGuiApplication::screens()[numscreen
]);
887 windowHandle()->setScreen(QGuiApplication::screens()[numscreen
]);
890 /* To be sure window is on proper-screen in xinerama */
891 if( !screenres
.contains( pos() ) )
893 lastWinPosition
= pos();
894 lastWinSize
= size();
895 msg_Dbg( p_intf
, "Moving video to correct position");
896 move( QPoint( screenres
.x(), screenres
.y() ) );
900 if( playlistWidget
!= NULL
&& playlistWidget
->artContainer
->currentWidget() == videoWidget
)
902 showTab( videoWidget
);
908 setInterfaceFullScreen( true );
912 setMinimalView( b_minimalView
);
913 setInterfaceFullScreen( b_interfaceFullScreen
);
914 #ifdef QT5_HAS_WAYLAND
915 if( lastWinScreen
!= NULL
&& !b_hasWayland
)
916 windowHandle()->setScreen(lastWinScreen
);
918 if( lastWinScreen
!= NULL
)
919 windowHandle()->setScreen(lastWinScreen
);
921 if( lastWinPosition
.isNull() == false )
923 move( lastWinPosition
);
924 resizeWindow( lastWinSize
.width(), lastWinSize
.height() );
925 lastWinPosition
= QPoint();
926 lastWinSize
= QSize();
933 void MainInterface::setHideMouse( bool hide
)
935 videoWidget
->setCursor( hide
? Qt::BlankCursor
: Qt::ArrowCursor
);
938 /* Slot to change the video always-on-top flag.
939 * Emit askVideoOnTop() to invoke this from other thread. */
940 void MainInterface::setVideoOnTop( bool on_top
)
942 //don't apply changes if user has already sets its interface on top
943 if ( b_interfaceOnTop
)
946 Qt::WindowFlags oldflags
= windowFlags(), newflags
;
949 newflags
= oldflags
| Qt::WindowStaysOnTopHint
;
951 newflags
= oldflags
& ~Qt::WindowStaysOnTopHint
;
952 if( newflags
!= oldflags
&& !b_videoFullScreen
)
954 setWindowFlags( newflags
);
955 show(); /* necessary to apply window flags */
959 void MainInterface::setInterfaceAlwaysOnTop( bool on_top
)
961 b_interfaceOnTop
= on_top
;
962 Qt::WindowFlags oldflags
= windowFlags(), newflags
;
965 newflags
= oldflags
| Qt::WindowStaysOnTopHint
;
967 newflags
= oldflags
& ~Qt::WindowStaysOnTopHint
;
968 if( newflags
!= oldflags
&& !b_videoFullScreen
)
970 setWindowFlags( newflags
);
971 show(); /* necessary to apply window flags */
975 /* Asynchronous call from WindowControl function */
976 int MainInterface::controlVideo( int i_query
, va_list args
)
980 case VOUT_WINDOW_SET_SIZE
:
982 unsigned int i_width
= va_arg( args
, unsigned int );
983 unsigned int i_height
= va_arg( args
, unsigned int );
985 emit
askVideoToResize( i_width
, i_height
);
988 case VOUT_WINDOW_SET_STATE
:
990 unsigned i_arg
= va_arg( args
, unsigned );
991 unsigned on_top
= i_arg
& VOUT_WINDOW_STATE_ABOVE
;
993 emit
askVideoOnTop( on_top
!= 0 );
996 case VOUT_WINDOW_SET_FULLSCREEN
:
998 bool b_fs
= va_arg( args
, int );
1000 emit
askVideoSetFullScreen( b_fs
);
1003 case VOUT_WINDOW_HIDE_MOUSE
:
1005 bool b_hide
= va_arg( args
, int );
1007 emit
askHideMouse( b_hide
);
1011 msg_Warn( p_intf
, "unsupported control query" );
1012 return VLC_EGENERIC
;
1016 /*****************************************************************************
1017 * Playlist, Visualisation and Menus handling
1018 *****************************************************************************/
1020 * Toggle the playlist widget or dialog
1022 void MainInterface::createPlaylist()
1024 PlaylistDialog
*dialog
= PlaylistDialog::getInstance( p_intf
);
1028 playlistWidget
= dialog
->exportPlaylistWidget();
1029 stackCentralW
->addWidget( playlistWidget
);
1030 stackWidgetsSizes
[playlistWidget
] = settings
->value( "playlistSize", QSize( 600, 300 ) ).toSize();
1032 CONNECT( dialog
, visibilityChanged(bool), this, setPlaylistVisibility(bool) );
1035 void MainInterface::togglePlaylist()
1037 if( !playlistWidget
) createPlaylist();
1039 PlaylistDialog
*dialog
= PlaylistDialog::getInstance( p_intf
);
1042 if ( dialog
->hasPlaylistWidget() )
1043 playlistWidget
= dialog
->exportPlaylistWidget();
1044 /* Playlist is not visible, show it */
1045 if( stackCentralW
->currentWidget() != playlistWidget
)
1047 if( stackCentralW
->indexOf( playlistWidget
) == -1 )
1048 stackCentralW
->addWidget( playlistWidget
);
1049 showTab( playlistWidget
);
1053 restoreStackOldWidget();
1055 playlistVisible
= ( stackCentralW
->currentWidget() == playlistWidget
);
1059 playlistVisible
= !playlistVisible
;
1060 if ( ! dialog
->hasPlaylistWidget() )
1061 dialog
->importPlaylistWidget( playlistWidget
);
1062 if ( playlistVisible
)
1070 const Qt::Key
MainInterface::kc
[10] =
1072 Qt::Key_Up
, Qt::Key_Up
,
1073 Qt::Key_Down
, Qt::Key_Down
,
1074 Qt::Key_Left
, Qt::Key_Right
, Qt::Key_Left
, Qt::Key_Right
,
1075 Qt::Key_B
, Qt::Key_A
1078 void MainInterface::dockPlaylist( bool p_docked
)
1080 if( b_plDocked
== p_docked
) return;
1081 /* some extra check */
1082 if ( b_plDocked
&& !playlistWidget
) createPlaylist();
1084 b_plDocked
= p_docked
;
1085 PlaylistDialog
*dialog
= PlaylistDialog::getInstance( p_intf
);
1087 if( !p_docked
) /* Previously docked */
1089 playlistVisible
= playlistWidget
->isVisible();
1091 /* repositioning the videowidget __before__ exporting the
1092 playlistwidget into the playlist dialog avoids two unneeded
1093 calls to the server in the qt library to reparent the underlying
1094 native window back and forth.
1095 For Wayland, this is mandatory since reparenting is not implemented.
1096 For X11 or Windows, this is just an optimization. */
1097 if ( videoWidget
&& THEMIM
->getIM()->hasVideo() )
1098 showTab(videoWidget
);
1102 /* playlistwidget exported into the playlist dialog */
1103 stackCentralW
->removeWidget( playlistWidget
);
1104 dialog
->importPlaylistWidget( playlistWidget
);
1105 if ( playlistVisible
) dialog
->show();
1107 else /* Previously undocked */
1109 playlistVisible
= dialog
->isVisible() && !( videoWidget
&& THEMIM
->getIM()->hasVideo() );
1111 playlistWidget
= dialog
->exportPlaylistWidget();
1112 stackCentralW
->addWidget( playlistWidget
);
1114 /* If playlist is invisible don't show it */
1115 if( playlistVisible
) showTab( playlistWidget
);
1120 * displayNormalView is the private function used by
1121 * the SLOT setVideoFullScreen to restore the menuBar
1122 * if minimal view is off
1124 void MainInterface::displayNormalView()
1126 menuBar()->setVisible( false );
1127 controls
->setVisible( false );
1128 statusBar()->setVisible( false );
1129 inputC
->setVisible( false );
1133 * setMinimalView is the private function used by
1134 * the SLOT toggleMinimalView
1136 void MainInterface::setMinimalView( bool b_minimal
)
1138 bool b_menuBarVisible
= menuBar()->isVisible();
1139 bool b_controlsVisible
= controls
->isVisible();
1140 bool b_statusBarVisible
= statusBar()->isVisible();
1141 bool b_inputCVisible
= inputC
->isVisible();
1143 if( !isFullScreen() && !isMaximized() && b_minimal
&& !b_isWindowTiled
)
1145 int i_heightChange
= 0;
1147 if( b_menuBarVisible
)
1148 i_heightChange
+= menuBar()->height();
1149 if( b_controlsVisible
)
1150 i_heightChange
+= controls
->height();
1151 if( b_statusBarVisible
)
1152 i_heightChange
+= statusBar()->height();
1153 if( b_inputCVisible
)
1154 i_heightChange
+= inputC
->height();
1156 if( i_heightChange
!= 0 )
1157 resizeWindow( width(), height() - i_heightChange
);
1160 menuBar()->setVisible( !b_minimal
);
1161 controls
->setVisible( !b_minimal
);
1162 statusBar()->setVisible( !b_minimal
&& b_statusbarVisible
);
1163 inputC
->setVisible( !b_minimal
);
1165 if( !isFullScreen() && !isMaximized() && !b_minimal
&& !b_isWindowTiled
)
1167 int i_heightChange
= 0;
1169 if( !b_menuBarVisible
&& menuBar()->isVisible() )
1170 i_heightChange
+= menuBar()->height();
1171 if( !b_controlsVisible
&& controls
->isVisible() )
1172 i_heightChange
+= controls
->height();
1173 if( !b_statusBarVisible
&& statusBar()->isVisible() )
1174 i_heightChange
+= statusBar()->height();
1175 if( !b_inputCVisible
&& inputC
->isVisible() )
1176 i_heightChange
+= inputC
->height();
1178 if( i_heightChange
!= 0 )
1179 resizeWindow( width(), height() + i_heightChange
);
1184 * This public SLOT is used for moving to minimal View Mode
1186 * If b_minimal is false, then we are normalView
1188 void MainInterface::toggleMinimalView( bool b_minimal
)
1190 if( !b_minimalView
&& b_autoresize
) /* Normal mode */
1192 if( stackCentralW
->currentWidget() == bgWidget
)
1194 if( stackCentralW
->height() < 16 )
1196 resizeStack( stackCentralW
->width(), 100 );
1200 b_minimalView
= b_minimal
;
1201 if( !b_videoFullScreen
)
1203 setMinimalView( b_minimalView
);
1204 computeMinimumSize();
1207 emit
minimalViewToggled( b_minimalView
);
1210 /* toggling advanced controls buttons */
1211 void MainInterface::toggleAdvancedButtons()
1213 controls
->toggleAdvanced();
1214 // if( fullscreenControls ) fullscreenControls->toggleAdvanced();
1217 /* Get the visibility status of the controls (hidden or not, advanced or not) */
1218 int MainInterface::getControlsVisibilityStatus()
1220 if( !controls
) return 0;
1221 return( (controls
->isVisible() ? CONTROLS_VISIBLE
: CONTROLS_HIDDEN
)
1222 + CONTROLS_ADVANCED
* controls
->b_advancedVisible
);
1225 StandardPLPanel
*MainInterface::getPlaylistView()
1227 if( !playlistWidget
) return NULL
;
1228 else return playlistWidget
->mainView
;
1231 void MainInterface::setStatusBarVisibility( bool b_visible
)
1233 statusBar()->setVisible( b_visible
);
1234 b_statusbarVisible
= b_visible
;
1235 if( controls
) controls
->setGripVisible( !b_statusbarVisible
);
1239 void MainInterface::setPlaylistVisibility( bool b_visible
)
1241 if( isPlDocked() || THEDP
->isDying() || (playlistWidget
&& playlistWidget
->isMinimized() ) )
1244 playlistVisible
= b_visible
;
1247 /************************************************************************
1249 ************************************************************************/
1250 void MainInterface::setName( const QString
& name
)
1252 input_name
= name
; /* store it for the QSystray use */
1253 /* Display it in the status bar, but also as a Tooltip in case it doesn't
1255 nameLabel
->setText( name
);
1256 nameLabel
->setToolTip( name
);
1260 * Give the decorations of the Main Window a correct Name.
1261 * If nothing is given, set it to VLC...
1263 void MainInterface::setVLCWindowsTitle( const QString
& aTitle
)
1265 if( aTitle
.isEmpty() )
1267 setWindowTitle( qtr( "VLC media player" ) );
1271 setWindowTitle( aTitle
+ " - " + qtr( "VLC media player" ) );
1275 void MainInterface::showCryptedLabel( bool b_show
)
1277 if( cryptedLabel
== NULL
)
1279 cryptedLabel
= new QLabel
;
1280 // The lock icon is not the right one for DRM protection/scrambled.
1281 //cryptedLabel->setPixmap( QPixmap( ":/lock.svg" ) );
1282 cryptedLabel
->setText( "DRM" );
1283 statusBar()->addWidget( cryptedLabel
);
1286 cryptedLabel
->setVisible( b_show
);
1289 void MainInterface::showBuffering( float f_cache
)
1291 QString amount
= QString("Buffering: %1%").arg( (int)(100*f_cache
) );
1292 statusBar()->showMessage( amount
, 1000 );
1295 /*****************************************************************************
1296 * Systray Icon and Systray Menu
1297 *****************************************************************************/
1299 * Create a SystemTray icon and a menu that would go with it.
1300 * Connects to a click handler on the icon.
1302 void MainInterface::createSystray()
1305 if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY
&& var_InheritBool( p_intf
, "qt-icon-change" ) )
1306 iconVLC
= QIcon::fromTheme( "vlc-xmas", QIcon( ":/logo/vlc128-xmas.png" ) );
1308 iconVLC
= QIcon::fromTheme( "vlc", QIcon( ":/logo/vlc256.png" ) );
1309 sysTray
= new QSystemTrayIcon( iconVLC
, this );
1310 sysTray
->setToolTip( qtr( "VLC media player" ));
1312 systrayMenu
= new QMenu( qtr( "VLC media player" ), this );
1313 systrayMenu
->setIcon( iconVLC
);
1315 VLCMenuBar::updateSystrayMenu( this, p_intf
, true );
1318 CONNECT( sysTray
, activated( QSystemTrayIcon::ActivationReason
),
1319 this, handleSystrayClick( QSystemTrayIcon::ActivationReason
) );
1321 /* Connects on nameChanged() */
1322 CONNECT( THEMIM
->getIM(), nameChanged( const QString
& ),
1323 this, updateSystrayTooltipName( const QString
& ) );
1324 /* Connect PLAY_STATUS on the systray */
1325 CONNECT( THEMIM
->getIM(), playingStatusChanged( int ),
1326 this, updateSystrayTooltipStatus( int ) );
1329 void MainInterface::toggleUpdateSystrayMenuWhenVisible()
1334 void MainInterface::resizeWindow(int w
, int h
)
1336 #if ! HAS_QT510 && defined(QT5_HAS_X11)
1337 if( QX11Info::isPlatformX11() )
1340 qreal dpr
= devicePixelRatioF();
1342 qreal dpr
= devicePixelRatio();
1345 size
= size
.boundedTo(maximumSize()).expandedTo(minimumSize());
1346 /* X11 window managers are not required to accept geometry changes on
1347 * the top-level window. Unfortunately, Qt < 5.10 assumes that the
1348 * change will succeed, and resizes all sub-windows unconditionally.
1349 * By calling XMoveResizeWindow directly, Qt will not see our change
1350 * request until the ConfigureNotify event on success
1351 * and not at all if it is rejected. */
1352 XMoveResizeWindow( QX11Info::display(), winId(),
1353 geometry().x() * dpr
, geometry().y() * dpr
,
1354 (unsigned int)size
.width() * dpr
, (unsigned int)size
.height() * dpr
);
1362 * Updates the Systray Icon's menu and toggle the main interface
1364 void MainInterface::toggleUpdateSystrayMenu()
1366 /* If hidden, show it */
1372 else if( isMinimized() )
1380 /* Visible (possibly under other windows) */
1381 toggleUpdateSystrayMenuWhenVisible();
1384 VLCMenuBar::updateSystrayMenu( this, p_intf
);
1387 /* First Item of the systray menu */
1388 void MainInterface::showUpdateSystrayMenu()
1396 VLCMenuBar::updateSystrayMenu( this, p_intf
);
1399 /* First Item of the systray menu */
1400 void MainInterface::hideUpdateSystrayMenu()
1403 VLCMenuBar::updateSystrayMenu( this, p_intf
);
1406 /* Click on systray Icon */
1407 void MainInterface::handleSystrayClick(
1408 QSystemTrayIcon::ActivationReason reason
)
1412 case QSystemTrayIcon::Trigger
:
1413 case QSystemTrayIcon::DoubleClick
:
1415 VLCMenuBar::updateSystrayMenu( this, p_intf
);
1417 toggleUpdateSystrayMenu();
1420 case QSystemTrayIcon::MiddleClick
:
1421 sysTray
->showMessage( qtr( "VLC media player" ),
1422 qtr( "Control menu for the player" ),
1423 QSystemTrayIcon::Information
, 3000 );
1431 * Updates the name of the systray Icon tooltip.
1432 * Doesn't check if the systray exists, check before you call it.
1434 void MainInterface::updateSystrayTooltipName( const QString
& name
)
1436 if( name
.isEmpty() )
1438 sysTray
->setToolTip( qtr( "VLC media player" ) );
1442 sysTray
->setToolTip( name
);
1443 if( ( i_notificationSetting
== NOTIFICATION_ALWAYS
) ||
1444 ( i_notificationSetting
== NOTIFICATION_MINIMIZED
&& (isMinimized() || isHidden()) ) )
1446 sysTray
->showMessage( qtr( "VLC media player" ), name
,
1447 QSystemTrayIcon::NoIcon
, 3000 );
1451 VLCMenuBar::updateSystrayMenu( this, p_intf
);
1455 * Updates the status of the systray Icon tooltip.
1456 * Doesn't check if the systray exists, check before you call it.
1458 void MainInterface::updateSystrayTooltipStatus( int i_status
)
1463 sysTray
->setToolTip( input_name
);
1466 sysTray
->setToolTip( input_name
+ " - " + qtr( "Paused") );
1469 sysTray
->setToolTip( qtr( "VLC media player" ) );
1472 VLCMenuBar::updateSystrayMenu( this, p_intf
);
1475 void MainInterface::changeEvent(QEvent
*event
)
1477 if( event
->type() == QEvent::WindowStateChange
)
1479 QWindowStateChangeEvent
*windowStateChangeEvent
= static_cast<QWindowStateChangeEvent
*>(event
);
1480 Qt::WindowStates newState
= windowState();
1481 Qt::WindowStates oldState
= windowStateChangeEvent
->oldState();
1483 /* b_maximizedView stores if the window was maximized before entering fullscreen.
1484 * It is set when entering maximized mode, unset when leaving it to normal mode.
1485 * Upon leaving full screen, if b_maximizedView is set,
1486 * the window should be maximized again. */
1487 if( newState
& Qt::WindowMaximized
&&
1488 !( oldState
& Qt::WindowMaximized
) )
1489 b_maximizedView
= true;
1491 if( !( newState
& Qt::WindowMaximized
) &&
1492 oldState
& Qt::WindowMaximized
&&
1493 !b_videoFullScreen
)
1494 b_maximizedView
= false;
1496 if( !( newState
& Qt::WindowFullScreen
) &&
1497 oldState
& Qt::WindowFullScreen
&&
1504 if( newState
& Qt::WindowMinimized
)
1506 b_hasPausedWhenMinimized
= false;
1508 if( THEMIM
->getIM()->playingStatus() == PLAYING_S
&&
1509 THEMIM
->getIM()->hasVideo() && !THEMIM
->getIM()->hasVisualisation() &&
1512 b_hasPausedWhenMinimized
= true;
1516 else if( oldState
& Qt::WindowMinimized
&& !( newState
& Qt::WindowMinimized
) )
1518 if( b_hasPausedWhenMinimized
)
1525 QWidget::changeEvent(event
);
1528 /************************************************************************
1530 ************************************************************************/
1531 void MainInterface::dropEvent(QDropEvent
*event
)
1533 dropEventPlay( event
, true );
1539 * Event called if something is dropped onto a VLC window
1540 * \param event the event in question
1541 * \param b_play whether to play the file immediately
1542 * \param b_playlist true to add to playlist, false to add to media library
1545 void MainInterface::dropEventPlay( QDropEvent
*event
, bool b_play
, bool b_playlist
)
1547 if( event
->possibleActions() & ( Qt::CopyAction
| Qt::MoveAction
| Qt::LinkAction
) )
1548 event
->setDropAction( Qt::CopyAction
);
1552 const QMimeData
*mimeData
= event
->mimeData();
1554 /* D&D of a subtitles file, add it on the fly */
1555 if( mimeData
->urls().count() == 1 && THEMIM
->getIM()->hasInput() )
1557 if( !input_AddSlave( THEMIM
->getInput(), SLAVE_TYPE_SPU
,
1558 qtu( mimeData
->urls()[0].toString() ), true, true, true ) )
1565 bool first
= b_play
;
1566 foreach( const QUrl
&url
, mimeData
->urls() )
1570 QString mrl
= toURI( url
.toEncoded().constData() );
1572 QFileInfo
info( url
.toLocalFile() );
1573 if( info
.exists() && info
.isSymLink() )
1575 QString target
= info
.symLinkTarget();
1577 if( QFile::exists( target
) )
1579 url
= QUrl::fromLocalFile( target
);
1583 url
.setUrl( target
);
1585 mrl
= toURI( url
.toEncoded().constData() );
1588 if( mrl
.length() > 0 )
1590 Open::openMRL( p_intf
, mrl
, first
, b_playlist
);
1596 /* Browsers give content as text if you dnd the addressbar,
1597 so check if mimedata has valid url in text and use it
1598 if we didn't get any normal Urls()*/
1599 if( !mimeData
->hasUrls() && mimeData
->hasText() &&
1600 QUrl(mimeData
->text()).isValid() )
1602 QString mrl
= toURI( mimeData
->text() );
1603 Open::openMRL( p_intf
, mrl
, first
, b_playlist
);
1607 void MainInterface::dragEnterEvent(QDragEnterEvent
*event
)
1609 event
->acceptProposedAction();
1611 void MainInterface::dragMoveEvent(QDragMoveEvent
*event
)
1613 event
->acceptProposedAction();
1615 void MainInterface::dragLeaveEvent(QDragLeaveEvent
*event
)
1620 /************************************************************************
1622 ************************************************************************/
1623 void MainInterface::keyPressEvent( QKeyEvent
*e
)
1625 handleKeyPress( e
);
1627 /* easter eggs sequence handling */
1628 if ( e
->key() == kc
[ i_kc_offset
] )
1633 if ( i_kc_offset
== (sizeof( kc
) / sizeof( Qt::Key
)) )
1640 void MainInterface::handleKeyPress( QKeyEvent
*e
)
1642 if( ( ( e
->modifiers() & Qt::ControlModifier
) && ( e
->key() == Qt::Key_H
) ) ||
1643 ( b_minimalView
&& !b_videoFullScreen
&& e
->key() == Qt::Key_Escape
) )
1645 toggleMinimalView( !b_minimalView
);
1648 else if( ( e
->modifiers() & Qt::ControlModifier
) && ( e
->key() == Qt::Key_K
) &&
1651 playlistWidget
->setSearchFieldFocus();
1655 int i_vlck
= qtEventToVLCKey( e
);
1658 var_SetInteger( p_intf
->obj
.libvlc
, "key-pressed", i_vlck
);
1665 void MainInterface::wheelEvent( QWheelEvent
*e
)
1667 int i_vlckey
= qtWheelEventToVLCKey( e
);
1668 var_SetInteger( p_intf
->obj
.libvlc
, "key-pressed", i_vlckey
);
1672 void MainInterface::closeEvent( QCloseEvent
*e
)
1675 if ( b_minimalView
)
1676 setMinimalView( false );
1677 emit
askToQuit(); /* ask THEDP to quit, so we have a unique method */
1678 /* Accept session quit. Otherwise we break the desktop mamager. */
1682 bool MainInterface::eventFilter( QObject
*obj
, QEvent
*event
)
1684 if ( event
->type() == MainInterface::ToolbarsNeedRebuild
) {
1689 return QObject::eventFilter( obj
, event
);
1693 void MainInterface::toolBarConfUpdated()
1695 QApplication::postEvent( this, new QEvent( MainInterface::ToolbarsNeedRebuild
) );
1698 void MainInterface::setInterfaceFullScreen( bool fs
)
1701 setWindowState( windowState() | Qt::WindowFullScreen
);
1703 setWindowState( windowState() & ~Qt::WindowFullScreen
);
1705 void MainInterface::toggleInterfaceFullScreen()
1707 b_interfaceFullScreen
= !b_interfaceFullScreen
;
1708 if( !b_videoFullScreen
)
1709 setInterfaceFullScreen( b_interfaceFullScreen
);
1710 emit
fullscreenInterfaceToggled( b_interfaceFullScreen
);
1713 void MainInterface::emitBoss()
1717 void MainInterface::setBoss()
1730 void MainInterface::emitRaise()
1734 void MainInterface::setRaise()
1740 void MainInterface::voutReleaseMouseEvents()
1744 QPoint pos
= QCursor::pos();
1745 QPoint localpos
= videoWidget
->mapFromGlobal(pos
);
1746 int buttons
= QApplication::mouseButtons();
1748 while (buttons
!= 0)
1750 if ( (buttons
& 1) != 0 )
1752 QMouseEvent
new_e( QEvent::MouseButtonRelease
, localpos
,
1753 (Qt::MouseButton
)i_button
, (Qt::MouseButton
)i_button
, Qt::NoModifier
);
1754 QApplication::sendEvent(videoWidget
, &new_e
);
1763 /*****************************************************************************
1764 * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1765 * We don't show the menu directly here because we don't want the
1766 * caller to block for a too long time.
1767 *****************************************************************************/
1768 static int PopupMenuCB( vlc_object_t
*, const char *,
1769 vlc_value_t
, vlc_value_t new_val
, void *param
)
1771 intf_thread_t
*p_intf
= (intf_thread_t
*)param
;
1773 if( p_intf
->pf_show_dialog
)
1775 p_intf
->pf_show_dialog( p_intf
, INTF_DIALOG_POPUPMENU
,
1776 new_val
.b_bool
, NULL
);
1782 /*****************************************************************************
1783 * IntfShowCB: callback triggered by the intf-toggle-fscontrol libvlc variable.
1784 *****************************************************************************/
1785 static int IntfShowCB( vlc_object_t
*, const char *,
1786 vlc_value_t
, vlc_value_t
, void *param
)
1788 intf_thread_t
*p_intf
= (intf_thread_t
*)param
;
1789 p_intf
->p_sys
->p_mi
->toggleFSC();
1795 /*****************************************************************************
1796 * IntfRaiseMainCB: callback triggered by the intf-show-main libvlc variable.
1797 *****************************************************************************/
1798 static int IntfRaiseMainCB( vlc_object_t
*, const char *,
1799 vlc_value_t
, vlc_value_t
, void *param
)
1801 intf_thread_t
*p_intf
= (intf_thread_t
*)param
;
1802 p_intf
->p_sys
->p_mi
->emitRaise();
1807 /*****************************************************************************
1808 * IntfBossCB: callback triggered by the intf-boss libvlc variable.
1809 *****************************************************************************/
1810 static int IntfBossCB( vlc_object_t
*, const char *,
1811 vlc_value_t
, vlc_value_t
, void *param
)
1813 intf_thread_t
*p_intf
= (intf_thread_t
*)param
;
1814 p_intf
->p_sys
->p_mi
->emitBoss();