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
39 #include "components/interface_widgets.hpp" // bgWidget, videoWidget
40 #include "components/controller.hpp" // controllers
41 #include "components/playlist/playlist.hpp" // plWidget
42 #include "dialogs/firstrun.hpp" // First Run
43 #include "dialogs/playlist.hpp" // PlaylistDialog
45 #include "menus.hpp" // Menu creation
46 #include "recents.hpp" // RecentItems when DnD
48 #include <QCloseEvent>
60 #include <QStackedWidget>
63 #include <vlc_keys.h> /* Wheel event */
64 #include <vlc_vout_display.h> /* vout_thread_t and VOUT_ events */
67 #if defined(_WIN32) && HAS_QT5
69 #include <qpa/qplatformnativeinterface.h>
74 /* Callback prototypes */
75 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
76 vlc_value_t old_val, vlc_value_t new_val, void *param );
77 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
78 vlc_value_t old_val, vlc_value_t new_val, void *param );
79 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
80 vlc_value_t old_val, vlc_value_t new_val, void *param );
81 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
82 vlc_value_t old_val, vlc_value_t new_val,
85 const QEvent::Type MainInterface::ToolbarsNeedRebuild =
86 (QEvent::Type)QEvent::registerEventType();
88 MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
90 /* Variables initialisation */
93 playlistWidget = NULL;
94 stackCentralOldWidget= NULL;
96 fullscreenControls = NULL;
101 b_hideAfterCreation = false; // --qt-start-minimized
102 playlistVisible = false;
104 b_interfaceFullScreen= false;
105 b_hasPausedWhenMinimized = false;
108 /* Ask for Privacy */
109 FirstRun::CheckAndRun( this, p_intf );
112 * Configuration and settings
113 * Pre-building of interface
116 setFocusPolicy( Qt::StrongFocus );
117 setAcceptDrops( true );
118 setWindowRole( "vlc-main" );
119 setWindowIcon( QApplication::windowIcon() );
120 setWindowOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
122 setAttribute( Qt::WA_MacBrushedMetal );
125 /* Is video in embedded in the UI or not */
126 b_videoEmbedded = var_InheritBool( p_intf, "embedded-video" );
128 /* Does the interface resize to video size or the opposite */
129 b_autoresize = var_InheritBool( p_intf, "qt-video-autoresize" );
131 /* Are we in the enhanced always-video mode or not ? */
132 b_minimalView = var_InheritBool( p_intf, "qt-minimal-view" );
134 /* Do we want anoying popups or not */
135 i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
138 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
140 /* Set the other interface settings */
141 settings = getSettings();
145 p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
149 b_plDocked = getSettings()->value( "MainWindow/pl-dock-status", true ).toBool();
152 /**************************
153 * UI and Widgets design
154 **************************/
155 setVLCWindowsTitle();
160 VLCMenuBar::createMenuBar( this, p_intf );
161 CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
162 this, destroyPopupMenu() );
164 createMainWidget( settings );
170 setStatusBarVisibility( getSettings()->value( "MainWindow/status-bar-visible", false ).toBool() );
175 taskbar_wmsg = RegisterWindowMessage(TEXT("TaskbarButtonCreated"));
178 /*********************************
179 * Create the Systray Management *
180 *********************************/
183 /*************************************************************
184 * Connect the input manager to the GUI elements it manages *
185 * Beware initSystray did some connects on input manager too *
186 *************************************************************/
188 * Connects on nameChanged()
189 * Those connects are different because options can impeach them to trigger.
191 /* Main Interface statusbar */
192 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
193 this, setName( const QString& ) );
194 /* and title of the Main Interface*/
195 if( var_InheritBool( p_intf, "qt-name-in-title" ) )
197 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
198 this, setVLCWindowsTitle( const QString& ) );
200 /* END CONNECTS ON IM */
202 /* VideoWidget connects for asynchronous calls */
203 b_videoFullScreen = false;
204 connect( this, SIGNAL(askGetVideo(WId*,int*,int*,unsigned*,unsigned *)),
205 this, SLOT(getVideoSlot(WId*,int*,int*,unsigned*,unsigned*)),
206 Qt::BlockingQueuedConnection );
207 connect( this, SIGNAL(askReleaseVideo( void )),
208 this, SLOT(releaseVideoSlot( void )),
209 Qt::BlockingQueuedConnection );
210 CONNECT( this, askVideoOnTop(bool), this, setVideoOnTop(bool));
216 CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
217 this, setVideoSize( unsigned int, unsigned int ) );
218 CONNECT( videoWidget, sizeChanged( int, int ),
219 this, videoSizeChanged( int, int ) );
221 CONNECT( this, askVideoSetFullScreen( bool ),
222 this, setVideoFullScreen( bool ) );
225 CONNECT( THEDP, toolBarConfUpdated(), this, toolBarConfUpdated() );
226 installEventFilter( this );
228 CONNECT( this, askToQuit(), THEDP, quit() );
230 CONNECT( this, askBoss(), this, setBoss() );
231 CONNECT( this, askRaise(), this, setRaise() );
233 /** END of CONNECTS**/
239 var_AddCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
240 var_AddCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
241 var_AddCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
243 /* Register callback for the intf-popupmenu variable */
244 var_AddCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
247 /* Final Sizing, restoration and placement of the interface */
248 if( settings->value( "MainWindow/playlist-visible", false ).toBool() )
251 QVLCTools::restoreWidgetPosition( settings, this, QSize(600, 420) );
253 b_interfaceFullScreen = isFullScreen();
255 setVisible( !b_hideAfterCreation );
257 /* Switch to minimal view if needed, must be called after the show() */
259 toggleMinimalView( true );
261 computeMinimumSize();
264 MainInterface::~MainInterface()
266 /* Unsure we hide the videoWidget before destroying it */
267 if( stackCentralOldWidget == videoWidget )
275 ImageList_Destroy( himl );
281 /* Be sure to kill the actionsManager... Only used in the MI and control */
282 ActionsManager::killInstance();
284 /* Delete the FSC controller */
285 delete fullscreenControls;
289 settings->beginGroup("MainWindow");
290 settings->setValue( "pl-dock-status", b_plDocked );
292 /* Save playlist state */
293 settings->setValue( "playlist-visible", playlistVisible );
295 settings->setValue( "adv-controls",
296 getControlsVisibilityStatus() & CONTROLS_ADVANCED );
297 settings->setValue( "status-bar-visible", b_statusbarVisible );
299 /* Save the stackCentralW sizes */
300 settings->setValue( "bgSize", stackWidgetsSizes[bgWidget] );
301 settings->setValue( "playlistSize", stackWidgetsSizes[playlistWidget] );
302 settings->endGroup();
305 QVLCTools::saveWidgetPosition(settings, this);
309 /* Unregister callbacks */
310 var_DelCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
311 var_DelCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
312 var_DelCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
313 var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
315 p_intf->p_sys->p_mi = NULL;
318 void MainInterface::computeMinimumSize()
321 if( menuBar()->isVisible() )
322 minWidth += controls->sizeHint().width();
324 setMinimumWidth( minWidth );
327 /*****************************
329 *****************************/
330 void MainInterface::recreateToolbars()
332 bool b_adv = getControlsVisibilityStatus() & CONTROLS_ADVANCED;
337 controls = new ControlsWidget( p_intf, b_adv, this );
338 inputC = new InputControlsWidget( p_intf, this );
339 mainLayout->insertWidget( 2, inputC );
340 mainLayout->insertWidget( settings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
343 if( fullscreenControls )
345 delete fullscreenControls;
346 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
347 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
348 this, handleKeyPress( QKeyEvent * ) );
349 THEMIM->requestVoutUpdate();
352 setMinimalView( b_minimalView );
355 void MainInterface::reloadPrefs()
357 i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
358 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
360 p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
362 if( !var_InheritBool( p_intf, "qt-fs-controller" ) && fullscreenControls )
364 delete fullscreenControls;
365 fullscreenControls = NULL;
369 void MainInterface::createMainWidget( QSettings *creationSettings )
371 /* Create the main Widget and the mainLayout */
372 QWidget *main = new QWidget;
373 setCentralWidget( main );
374 mainLayout = new QVBoxLayout( main );
375 main->setContentsMargins( 0, 0, 0, 0 );
376 mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
379 stackCentralW = new QVLCStackedWidget( main );
382 if ( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY
383 && var_InheritBool( p_intf, "qt-icon-change" ) )
385 bgWidget = new EasterEggBackgroundWidget( p_intf );
386 CONNECT( this, kc_pressed(), bgWidget, animate() );
389 bgWidget = new BackgroundWidget( p_intf );
391 stackCentralW->addWidget( bgWidget );
392 if ( !var_InheritBool( p_intf, "qt-bgcone" ) )
393 bgWidget->setWithArt( false );
395 if ( var_InheritBool( p_intf, "qt-bgcone-expands" ) )
396 bgWidget->setExpandstoHeight( true );
398 /* And video Outputs */
399 if( b_videoEmbedded )
401 videoWidget = new VideoWidget( p_intf );
402 stackCentralW->addWidget( videoWidget );
404 mainLayout->insertWidget( 1, stackCentralW );
406 stackWidgetsSizes[bgWidget] =
407 creationSettings->value( "MainWindow/bgSize", QSize( 600, 0 ) ).toSize();
408 /* Resize even if no-auto-resize, because we are at creation */
409 resizeStack( stackWidgetsSizes[bgWidget].width(), stackWidgetsSizes[bgWidget].height() );
411 /* Create the CONTROLS Widget */
412 controls = new ControlsWidget( p_intf,
413 creationSettings->value( "MainWindow/adv-controls", false ).toBool(), this );
414 inputC = new InputControlsWidget( p_intf, this );
416 mainLayout->insertWidget( 2, inputC );
417 mainLayout->insertWidget(
418 creationSettings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
421 /* Visualisation, disabled for now, they SUCK */
423 visualSelector = new VisualSelector( p_intf );
424 mainLayout->insertWidget( 0, visualSelector );
425 visualSelector->hide();
429 /* Enable the popup menu in the MI */
430 main->setContextMenuPolicy( Qt::CustomContextMenu );
431 CONNECT( main, customContextMenuRequested( const QPoint& ),
432 this, popupMenu( const QPoint& ) );
434 if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
435 /* Create the FULLSCREEN CONTROLS Widget */
436 if( var_InheritBool( p_intf, "qt-fs-controller" ) )
438 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
439 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
440 this, handleKeyPress( QKeyEvent * ) );
444 inline void MainInterface::initSystray()
446 bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
447 bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
449 if( var_InheritBool( p_intf, "qt-start-minimized") )
451 if( b_systrayAvailable )
453 b_systrayWanted = true;
454 b_hideAfterCreation = true;
457 msg_Err( p_intf, "cannot start minimized without system tray bar" );
460 if( b_systrayAvailable && b_systrayWanted )
464 inline void MainInterface::createStatusBar()
469 /* Widgets Creation*/
470 QStatusBar *statusBarr = statusBar();
472 TimeLabel *timeLabel = new TimeLabel( p_intf );
473 nameLabel = new ClickableQLabel();
474 nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
475 | Qt::TextSelectableByKeyboard );
476 SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
478 /* Styling those labels */
479 timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
480 speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
481 nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
482 timeLabel->setStyleSheet(
483 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
484 speedLabel->setStyleSheet(
485 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
486 /* pad both label and its tooltip */
487 nameLabel->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
489 /* and adding those */
490 statusBarr->addWidget( nameLabel, 8 );
491 statusBarr->addPermanentWidget( speedLabel, 0 );
492 statusBarr->addPermanentWidget( timeLabel, 0 );
494 CONNECT( nameLabel, doubleClicked(), THEDP, epgDialog() );
495 /* timeLabel behaviour:
496 - double clicking opens the goto time dialog
497 - right-clicking and clicking just toggle between remaining and
499 CONNECT( timeLabel, doubleClicked(), THEDP, gotoTimeDialog() );
501 CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
502 this, showCryptedLabel( bool ) );
504 CONNECT( THEMIM->getIM(), seekRequested( float ),
505 timeLabel, setDisplayPosition( float ) );
507 /* This shouldn't be necessary, but for somehow reason, the statusBarr
508 starts at height of 20px and when a text is shown it needs more space.
509 But, as the QMainWindow policy doesn't allow statusBar to change QMW's
510 geometry, we need to force a height. If you have a better idea, please
513 statusBarr->setFixedHeight( statusBarr->sizeHint().height() + 2 );
516 /**********************************************************************
517 * Handling of sizing of the components
518 **********************************************************************/
520 void MainInterface::debug()
524 msg_Dbg( p_intf, "Controls size: %i - %i", controls->size().height(), controls->size().width() );
525 msg_Dbg( p_intf, "Controls minimumsize: %i - %i", controls->minimumSize().height(), controls->minimumSize().width() );
526 msg_Dbg( p_intf, "Controls sizeHint: %i - %i", controls->sizeHint().height(), controls->sizeHint().width() );
529 msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
530 msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
531 msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
533 msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
534 msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
535 msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
539 inline void MainInterface::showVideo() { showTab( videoWidget ); setRaise(); }
540 inline void MainInterface::restoreStackOldWidget()
541 { showTab( stackCentralOldWidget ); }
543 inline void MainInterface::showTab( QWidget *widget )
545 if ( !widget ) widget = bgWidget; /* trying to restore a null oldwidget */
547 if ( stackCentralOldWidget )
548 msg_Dbg( p_intf, "Old stackCentralOldWidget %s at index %i",
549 stackCentralOldWidget->metaObject()->className(),
550 stackCentralW->indexOf( stackCentralOldWidget ) );
551 msg_Dbg( p_intf, "ShowTab request for %s", widget->metaObject()->className() );
553 /* fixing when the playlist has been undocked after being hidden.
554 restoreStackOldWidget() is called when video stops but
555 stackCentralOldWidget would still be pointing to playlist */
556 if ( widget == playlistWidget && !isPlDocked() )
559 stackCentralOldWidget = stackCentralW->currentWidget();
560 stackWidgetsSizes[stackCentralOldWidget] = stackCentralW->size();
562 /* If we are playing video, embedded */
563 if( videoWidget && THEMIM->getIM()->hasVideo() )
565 /* Video -> Playlist */
566 if( videoWidget == stackCentralOldWidget && widget == playlistWidget )
568 stackCentralW->removeWidget( videoWidget );
569 videoWidget->show(); videoWidget->raise();
572 /* Playlist -> Video */
573 if( playlistWidget == stackCentralOldWidget && widget == videoWidget )
575 playlistWidget->artContainer->removeWidget( videoWidget );
576 videoWidget->show(); videoWidget->raise();
577 stackCentralW->addWidget( videoWidget );
580 /* Embedded playlist -> Non-embedded playlist */
581 if( bgWidget == stackCentralOldWidget && widget == videoWidget )
583 /* In rare case when video is started before the interface */
584 if( playlistWidget != NULL )
585 playlistWidget->artContainer->removeWidget( videoWidget );
586 videoWidget->show(); videoWidget->raise();
587 stackCentralW->addWidget( videoWidget );
588 stackCentralW->setCurrentWidget( videoWidget );
592 stackCentralW->setCurrentWidget( widget );
594 resizeStack( stackWidgetsSizes[widget].width(), stackWidgetsSizes[widget].height() );
597 msg_Dbg( p_intf, "Stack state changed to %s, index %i",
598 stackCentralW->currentWidget()->metaObject()->className(),
599 stackCentralW->currentIndex() );
600 msg_Dbg( p_intf, "New stackCentralOldWidget %s at index %i",
601 stackCentralOldWidget->metaObject()->className(),
602 stackCentralW->indexOf( stackCentralOldWidget ) );
605 /* This part is done later, to account for the new pl size */
606 if( videoWidget && THEMIM->getIM()->hasVideo() &&
607 videoWidget == stackCentralOldWidget && widget == playlistWidget )
609 playlistWidget->artContainer->addWidget( videoWidget );
610 playlistWidget->artContainer->setCurrentWidget( videoWidget );
614 void MainInterface::destroyPopupMenu()
616 VLCMenuBar::PopupMenu( p_intf, false );
619 void MainInterface::popupMenu( const QPoint & )
621 VLCMenuBar::PopupMenu( p_intf, true );
624 void MainInterface::toggleFSC()
626 if( !fullscreenControls ) return;
628 IMEvent *eShow = new IMEvent( IMEvent::FullscreenControlToggle );
629 QApplication::postEvent( fullscreenControls, eShow );
632 /****************************************************************************
634 ****************************************************************************/
638 * You must not change the state of this object or other Qt UI objects,
639 * from the video output thread - only from the Qt UI main loop thread.
640 * All window provider queries must be handled through signals or events.
641 * That's why we have all those emit statements...
643 WId MainInterface::getVideo( int *pi_x, int *pi_y,
644 unsigned int *pi_width, unsigned int *pi_height )
649 /* This is a blocking call signal. Results are returned through pointers.
650 * Beware of deadlocks! */
652 emit askGetVideo( &id, pi_x, pi_y, pi_width, pi_height );
656 void MainInterface::getVideoSlot( WId *p_id, int *pi_x, int *pi_y,
657 unsigned *pi_width, unsigned *pi_height )
659 /* Hidden or minimized, activate */
660 if( isHidden() || isMinimized() )
661 toggleUpdateSystrayMenu();
663 /* Request the videoWidget */
664 WId ret = videoWidget->request( pi_x, pi_y,
665 pi_width, pi_height, !b_autoresize );
667 if( ret ) /* The videoWidget is available */
669 /* Consider the video active now */
672 /* Ask videoWidget to resize correctly, if we are in normal mode */
673 if( !isFullScreen() && !isMaximized() && b_autoresize )
674 videoWidget->SetSizing( *pi_width, *pi_height );
678 /* Asynchronous call from the WindowClose function */
679 void MainInterface::releaseVideo( void )
681 emit askReleaseVideo();
684 /* Function that is CONNECTED to the previous emit */
685 void MainInterface::releaseVideoSlot( void )
687 /* This function is called when the embedded video window is destroyed,
688 * or in the rare case that the embedded window is still here but the
689 * Qt interface exits. */
690 assert( videoWidget );
691 videoWidget->release();
692 setVideoOnTop( false );
693 setVideoFullScreen( false );
695 if( stackCentralW->currentWidget() == videoWidget )
696 restoreStackOldWidget();
697 else if( playlistWidget &&
698 playlistWidget->artContainer->currentWidget() == videoWidget )
700 playlistWidget->artContainer->setCurrentIndex( 0 );
701 stackCentralW->addWidget( videoWidget );
704 /* We don't want to have a blank video to popup */
705 stackCentralOldWidget = bgWidget;
708 void MainInterface::setVideoSize( unsigned int w, unsigned int h )
710 if( !isFullScreen() && !isMaximized() )
711 videoWidget->SetSizing( w, h );
714 void MainInterface::videoSizeChanged( int w, int h )
716 if( !playlistWidget || playlistWidget->artContainer->currentWidget() != videoWidget )
720 void MainInterface::setVideoFullScreen( bool fs )
722 b_videoFullScreen = fs;
725 int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
726 /* if user hasn't defined screennumber, or screennumber that is bigger
727 * than current number of screens, take screennumber where current interface
730 if( numscreen == -1 || numscreen > QApplication::desktop()->numScreens() )
731 numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
733 QRect screenres = QApplication::desktop()->screenGeometry( numscreen );
735 /* To be sure window is on proper-screen in xinerama */
736 if( !screenres.contains( pos() ) )
738 msg_Dbg( p_intf, "Moving video to correct screen");
739 move( QPoint( screenres.x(), screenres.y() ) );
743 if( playlistWidget != NULL && playlistWidget->artContainer->currentWidget() == videoWidget )
745 showTab( videoWidget );
749 setMinimalView( true );
750 setInterfaceFullScreen( true );
754 /* TODO do we want to restore screen and position ? (when
755 * qt-fullscreen-screennumber is forced) */
756 setMinimalView( b_minimalView );
757 setInterfaceFullScreen( b_interfaceFullScreen );
762 /* Slot to change the video always-on-top flag.
763 * Emit askVideoOnTop() to invoke this from other thread. */
764 void MainInterface::setVideoOnTop( bool on_top )
766 Qt::WindowFlags oldflags = windowFlags(), newflags;
769 newflags = oldflags | Qt::WindowStaysOnTopHint;
771 newflags = oldflags & ~Qt::WindowStaysOnTopHint;
772 if( newflags != oldflags && !b_videoFullScreen )
775 setWindowFlags( newflags );
776 show(); /* necessary to apply window flags */
780 /* Asynchronous call from WindowControl function */
781 int MainInterface::controlVideo( int i_query, va_list args )
785 case VOUT_WINDOW_SET_SIZE:
787 unsigned int i_width = va_arg( args, unsigned int );
788 unsigned int i_height = va_arg( args, unsigned int );
790 emit askVideoToResize( i_width, i_height );
793 case VOUT_WINDOW_SET_STATE:
795 unsigned i_arg = va_arg( args, unsigned );
796 unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
798 emit askVideoOnTop( on_top != 0 );
801 case VOUT_WINDOW_SET_FULLSCREEN:
803 bool b_fs = va_arg( args, int );
805 emit askVideoSetFullScreen( b_fs );
809 msg_Warn( p_intf, "unsupported control query" );
814 /*****************************************************************************
815 * Playlist, Visualisation and Menus handling
816 *****************************************************************************/
818 * Toggle the playlist widget or dialog
820 void MainInterface::createPlaylist()
822 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
826 playlistWidget = dialog->exportPlaylistWidget();
827 stackCentralW->addWidget( playlistWidget );
828 stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 600, 300 ) ).toSize();
830 CONNECT( dialog, visibilityChanged(bool), this, setPlaylistVisibility(bool) );
833 void MainInterface::togglePlaylist()
835 if( !playlistWidget ) createPlaylist();
837 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
840 if ( dialog->hasPlaylistWidget() )
841 playlistWidget = dialog->exportPlaylistWidget();
842 /* Playlist is not visible, show it */
843 if( stackCentralW->currentWidget() != playlistWidget )
845 if( stackCentralW->indexOf( playlistWidget ) == -1 )
846 stackCentralW->addWidget( playlistWidget );
847 showTab( playlistWidget );
851 restoreStackOldWidget();
853 playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
857 playlistVisible = !playlistVisible;
858 if ( ! dialog->hasPlaylistWidget() )
859 dialog->importPlaylistWidget( playlistWidget );
860 if ( playlistVisible )
868 const Qt::Key MainInterface::kc[10] =
870 Qt::Key_Up, Qt::Key_Up,
871 Qt::Key_Down, Qt::Key_Down,
872 Qt::Key_Left, Qt::Key_Right, Qt::Key_Left, Qt::Key_Right,
876 void MainInterface::dockPlaylist( bool p_docked )
878 if( b_plDocked == p_docked ) return;
879 /* some extra check */
880 if ( b_plDocked && !playlistWidget ) createPlaylist();
882 b_plDocked = p_docked;
883 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
885 if( !p_docked ) /* Previously docked */
887 playlistVisible = playlistWidget->isVisible();
888 stackCentralW->removeWidget( playlistWidget );
889 dialog->importPlaylistWidget( playlistWidget );
890 if ( playlistVisible ) dialog->show();
891 restoreStackOldWidget();
893 else /* Previously undocked */
895 playlistVisible = dialog->isVisible();
897 playlistWidget = dialog->exportPlaylistWidget();
898 stackCentralW->addWidget( playlistWidget );
900 /* If playlist is invisible don't show it */
901 if( playlistVisible ) showTab( playlistWidget );
906 * setMinimalView is the private function used by
907 * the SLOT toggleMinimalView and setVideoFullScreen
909 void MainInterface::setMinimalView( bool b_minimal )
911 menuBar()->setVisible( !b_minimal );
912 controls->setVisible( !b_minimal );
913 statusBar()->setVisible( !b_minimal && b_statusbarVisible );
914 inputC->setVisible( !b_minimal );
918 * This public SLOT is used for moving to minimal View Mode
920 * If b_minimal is false, then we are normalView
922 void MainInterface::toggleMinimalView( bool b_minimal )
924 if( !b_minimalView && b_autoresize ) /* Normal mode */
926 if( stackCentralW->currentWidget() == bgWidget )
928 if( stackCentralW->height() < 16 )
930 resizeStack( stackCentralW->width(), 100 );
934 b_minimalView = b_minimal;
935 if( !b_videoFullScreen )
937 setMinimalView( b_minimalView );
938 computeMinimumSize();
941 emit minimalViewToggled( b_minimalView );
944 /* toggling advanced controls buttons */
945 void MainInterface::toggleAdvancedButtons()
947 controls->toggleAdvanced();
948 // if( fullscreenControls ) fullscreenControls->toggleAdvanced();
951 /* Get the visibility status of the controls (hidden or not, advanced or not) */
952 int MainInterface::getControlsVisibilityStatus()
954 if( !controls ) return 0;
955 return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
956 + CONTROLS_ADVANCED * controls->b_advancedVisible );
959 StandardPLPanel *MainInterface::getPlaylistView()
961 if( !playlistWidget ) return NULL;
962 else return playlistWidget->mainView;
965 void MainInterface::setStatusBarVisibility( bool b_visible )
967 statusBar()->setVisible( b_visible );
968 b_statusbarVisible = b_visible;
969 if( controls ) controls->setGripVisible( !b_statusbarVisible );
973 void MainInterface::setPlaylistVisibility( bool b_visible )
975 if( isPlDocked() || THEDP->isDying() || (playlistWidget && playlistWidget->isMinimized() ) )
978 playlistVisible = b_visible;
982 void MainInterface::visual()
984 if( !VISIBLE( visualSelector) )
986 visualSelector->show();
987 if( !THEMIM->getIM()->hasVideo() )
989 /* Show the background widget */
991 visualSelectorEnabled = true;
995 /* Stop any currently running visualization */
996 visualSelector->hide();
997 visualSelectorEnabled = false;
1002 /************************************************************************
1004 ************************************************************************/
1005 void MainInterface::setName( const QString& name )
1007 input_name = name; /* store it for the QSystray use */
1008 /* Display it in the status bar, but also as a Tooltip in case it doesn't
1010 nameLabel->setText( name );
1011 nameLabel->setToolTip( name );
1015 * Give the decorations of the Main Window a correct Name.
1016 * If nothing is given, set it to VLC...
1018 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
1020 if( aTitle.isEmpty() )
1022 setWindowTitle( qtr( "VLC media player" ) );
1026 setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
1030 void MainInterface::showCryptedLabel( bool b_show )
1032 if( cryptedLabel == NULL )
1034 cryptedLabel = new QLabel;
1035 // The lock icon is not the right one for DRM protection/scrambled.
1036 //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
1037 cryptedLabel->setText( "DRM" );
1038 statusBar()->addWidget( cryptedLabel );
1041 cryptedLabel->setVisible( b_show );
1044 void MainInterface::showBuffering( float f_cache )
1046 QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
1047 statusBar()->showMessage( amount, 1000 );
1050 /*****************************************************************************
1051 * Systray Icon and Systray Menu
1052 *****************************************************************************/
1054 * Create a SystemTray icon and a menu that would go with it.
1055 * Connects to a click handler on the icon.
1057 void MainInterface::createSystray()
1060 if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
1061 iconVLC = QIcon::fromTheme( "vlc-xmas", QIcon( ":/logo/vlc128-xmas.png" ) );
1063 iconVLC = QIcon::fromTheme( "vlc", QIcon( ":/logo/vlc256.png" ) );
1064 sysTray = new QSystemTrayIcon( iconVLC, this );
1065 sysTray->setToolTip( qtr( "VLC media player" ));
1067 systrayMenu = new QMenu( qtr( "VLC media player" ), this );
1068 systrayMenu->setIcon( iconVLC );
1070 VLCMenuBar::updateSystrayMenu( this, p_intf, true );
1073 CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
1074 this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
1076 /* Connects on nameChanged() */
1077 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
1078 this, updateSystrayTooltipName( const QString& ) );
1079 /* Connect PLAY_STATUS on the systray */
1080 CONNECT( THEMIM->getIM(), playingStatusChanged( int ),
1081 this, updateSystrayTooltipStatus( int ) );
1085 * Updates the Systray Icon's menu and toggle the main interface
1087 void MainInterface::toggleUpdateSystrayMenu()
1089 /* If hidden, show it */
1095 else if( isMinimized() )
1103 /* Visible (possibly under other windows) */
1105 /* check if any visible window is above vlc in the z-order,
1106 * but ignore the ones always on top
1107 * and the ones which can't be activated */
1110 QWindow *window = windowHandle();
1111 winId = static_cast<HWND>(QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", window));
1113 winId = internalWinId();
1118 wi.cbSize = sizeof( WINDOWINFO );
1119 for( hwnd = GetNextWindow( winId, GW_HWNDPREV );
1120 hwnd && ( !IsWindowVisible( hwnd ) ||
1121 ( GetWindowInfo( hwnd, &wi ) &&
1122 (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
1123 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
1124 if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
1125 (wi.dwExStyle&WS_EX_TOPMOST) )
1138 VLCMenuBar::updateSystrayMenu( this, p_intf );
1141 /* First Item of the systray menu */
1142 void MainInterface::showUpdateSystrayMenu()
1150 VLCMenuBar::updateSystrayMenu( this, p_intf );
1153 /* First Item of the systray menu */
1154 void MainInterface::hideUpdateSystrayMenu()
1157 VLCMenuBar::updateSystrayMenu( this, p_intf );
1160 /* Click on systray Icon */
1161 void MainInterface::handleSystrayClick(
1162 QSystemTrayIcon::ActivationReason reason )
1166 case QSystemTrayIcon::Trigger:
1167 case QSystemTrayIcon::DoubleClick:
1169 VLCMenuBar::updateSystrayMenu( this, p_intf );
1171 toggleUpdateSystrayMenu();
1174 case QSystemTrayIcon::MiddleClick:
1175 sysTray->showMessage( qtr( "VLC media player" ),
1176 qtr( "Control menu for the player" ),
1177 QSystemTrayIcon::Information, 3000 );
1185 * Updates the name of the systray Icon tooltip.
1186 * Doesn't check if the systray exists, check before you call it.
1188 void MainInterface::updateSystrayTooltipName( const QString& name )
1190 if( name.isEmpty() )
1192 sysTray->setToolTip( qtr( "VLC media player" ) );
1196 sysTray->setToolTip( name );
1197 if( ( i_notificationSetting == NOTIFICATION_ALWAYS ) ||
1198 ( i_notificationSetting == NOTIFICATION_MINIMIZED && (isMinimized() || isHidden()) ) )
1200 sysTray->showMessage( qtr( "VLC media player" ), name,
1201 QSystemTrayIcon::NoIcon, 3000 );
1205 VLCMenuBar::updateSystrayMenu( this, p_intf );
1209 * Updates the status of the systray Icon tooltip.
1210 * Doesn't check if the systray exists, check before you call it.
1212 void MainInterface::updateSystrayTooltipStatus( int i_status )
1217 sysTray->setToolTip( input_name );
1220 sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1223 sysTray->setToolTip( qtr( "VLC media player" ) );
1226 VLCMenuBar::updateSystrayMenu( this, p_intf );
1229 void MainInterface::changeEvent(QEvent *event)
1231 if( event->type() == QEvent::WindowStateChange )
1233 QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
1234 Qt::WindowStates newState = windowState();
1235 Qt::WindowStates oldState = windowStateChangeEvent->oldState();
1237 if( newState & Qt::WindowMinimized )
1239 b_hasPausedWhenMinimized = false;
1241 if( THEMIM->getIM()->playingStatus() == PLAYING_S &&
1242 THEMIM->getIM()->hasVideo() && !THEMIM->getIM()->hasVisualisation() &&
1245 b_hasPausedWhenMinimized = true;
1249 else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
1251 if( b_hasPausedWhenMinimized )
1258 QWidget::changeEvent(event);
1261 /************************************************************************
1263 ************************************************************************/
1264 void MainInterface::dropEvent(QDropEvent *event)
1266 dropEventPlay( event, true );
1272 * Event called if something is dropped onto a VLC window
1273 * \param event the event in question
1274 * \param b_play whether to play the file immediately
1275 * \param b_playlist true to add to playlist, false to add to media library
1278 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play, bool b_playlist )
1280 if( event->possibleActions() & ( Qt::CopyAction | Qt::MoveAction | Qt::LinkAction ) )
1281 event->setDropAction( Qt::CopyAction );
1285 const QMimeData *mimeData = event->mimeData();
1287 /* D&D of a subtitles file, add it on the fly */
1288 if( mimeData->urls().count() == 1 && THEMIM->getIM()->hasInput() )
1290 if( !input_AddSubtitleOSD( THEMIM->getInput(),
1291 qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1299 bool first = b_play;
1300 foreach( const QUrl &url, mimeData->urls() )
1304 QString mrl = toURI( url.toEncoded().constData() );
1305 QFileInfo info( url.toLocalFile() );
1306 if( info.exists() && info.isSymLink() )
1308 QString target = info.symLinkTarget();
1310 if( QFile::exists( target ) )
1312 url = QUrl::fromLocalFile( target );
1316 url.setUrl( target );
1318 mrl = toURI( url.toEncoded().constData() );
1320 if( mrl.length() > 0 )
1322 Open::openMRL( p_intf, mrl, first, b_playlist );
1328 /* Browsers give content as text if you dnd the addressbar,
1329 so check if mimedata has valid url in text and use it
1330 if we didn't get any normal Urls()*/
1331 if( !mimeData->hasUrls() && mimeData->hasText() &&
1332 QUrl(mimeData->text()).isValid() )
1334 QString mrl = toURI( mimeData->text() );
1335 Open::openMRL( p_intf, mrl, first, b_playlist );
1339 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1341 event->acceptProposedAction();
1343 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1345 event->acceptProposedAction();
1347 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1352 /************************************************************************
1354 ************************************************************************/
1355 void MainInterface::keyPressEvent( QKeyEvent *e )
1357 handleKeyPress( e );
1359 /* easter eggs sequence handling */
1360 if ( e->key() == kc[ i_kc_offset ] )
1365 if ( i_kc_offset == (sizeof( kc ) / sizeof( Qt::Key )) )
1372 void MainInterface::handleKeyPress( QKeyEvent *e )
1374 if( ( ( e->modifiers() & Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) ) ||
1375 ( b_minimalView && !b_videoFullScreen && e->key() == Qt::Key_Escape ) )
1377 toggleMinimalView( !b_minimalView );
1381 int i_vlck = qtEventToVLCKey( e );
1384 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1391 void MainInterface::wheelEvent( QWheelEvent *e )
1393 int i_vlckey = qtWheelEventToVLCKey( e );
1394 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1398 void MainInterface::closeEvent( QCloseEvent *e )
1401 emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
1402 /* Accept session quit. Otherwise we break the desktop mamager. */
1406 bool MainInterface::eventFilter( QObject *obj, QEvent *event )
1408 if ( event->type() == MainInterface::ToolbarsNeedRebuild ) {
1413 return QObject::eventFilter( obj, event );
1417 void MainInterface::toolBarConfUpdated()
1419 QApplication::postEvent( this, new QEvent( MainInterface::ToolbarsNeedRebuild ) );
1422 void MainInterface::setInterfaceFullScreen( bool fs )
1425 setWindowState( windowState() | Qt::WindowFullScreen );
1427 setWindowState( windowState() & ~Qt::WindowFullScreen );
1429 void MainInterface::toggleInterfaceFullScreen()
1431 b_interfaceFullScreen = !b_interfaceFullScreen;
1432 if( !b_videoFullScreen )
1433 setInterfaceFullScreen( b_interfaceFullScreen );
1434 emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1437 void MainInterface::emitBoss()
1441 void MainInterface::setBoss()
1454 void MainInterface::emitRaise()
1458 void MainInterface::setRaise()
1464 /*****************************************************************************
1465 * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1466 * We don't show the menu directly here because we don't want the
1467 * caller to block for a too long time.
1468 *****************************************************************************/
1469 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1470 vlc_value_t old_val, vlc_value_t new_val, void *param )
1472 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1474 intf_thread_t *p_intf = (intf_thread_t *)param;
1476 if( p_intf->pf_show_dialog )
1478 p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1479 new_val.b_bool, NULL );
1485 /*****************************************************************************
1486 * IntfShowCB: callback triggered by the intf-toggle-fscontrol libvlc variable.
1487 *****************************************************************************/
1488 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1489 vlc_value_t old_val, vlc_value_t new_val, void *param )
1491 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1492 VLC_UNUSED( new_val );
1494 intf_thread_t *p_intf = (intf_thread_t *)param;
1495 p_intf->p_sys->p_mi->toggleFSC();
1501 /*****************************************************************************
1502 * IntfRaiseMainCB: callback triggered by the intf-show-main libvlc variable.
1503 *****************************************************************************/
1504 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
1505 vlc_value_t old_val, vlc_value_t new_val, void *param )
1507 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1508 VLC_UNUSED( new_val );
1510 intf_thread_t *p_intf = (intf_thread_t *)param;
1511 p_intf->p_sys->p_mi->emitRaise();
1516 /*****************************************************************************
1517 * IntfBossCB: callback triggered by the intf-boss libvlc variable.
1518 *****************************************************************************/
1519 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
1520 vlc_value_t old_val, vlc_value_t new_val, void *param )
1522 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1523 VLC_UNUSED( new_val );
1525 intf_thread_t *p_intf = (intf_thread_t *)param;
1526 p_intf->p_sys->p_mi->emitBoss();