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
35 #include "extensions_manager.hpp" // killInstance
37 #include "util/customwidgets.hpp" // qtEventToVLCKey, QVLCStackedWidget
38 #include "util/qt_dirs.hpp" // toNativeSeparators
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
45 #include "menus.hpp" // Menu creation
46 #include "recents.hpp" // RecentItems when DnD
48 #include <QCloseEvent>
59 #include <QStackedWidget>
61 #include <vlc_keys.h> /* Wheel event */
62 #include <vlc_vout_display.h> /* vout_thread_t and VOUT_ events */
66 /* Callback prototypes */
67 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
68 vlc_value_t old_val, vlc_value_t new_val, void *param );
69 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
70 vlc_value_t old_val, vlc_value_t new_val, void *param );
71 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
72 vlc_value_t old_val, vlc_value_t new_val, void *param );
73 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
74 vlc_value_t old_val, vlc_value_t new_val,
77 MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
79 /* Variables initialisation */
82 playlistWidget = NULL;
83 stackCentralOldWidget= NULL;
85 fullscreenControls = NULL;
90 b_hideAfterCreation = false; // --qt-start-minimized
91 playlistVisible = false;
93 b_interfaceFullScreen= false;
94 b_hasPausedWhenMinimized = false;
98 FirstRun::CheckAndRun( this, p_intf );
101 * Configuration and settings
102 * Pre-building of interface
105 setFocusPolicy( Qt::StrongFocus );
106 setAcceptDrops( true );
107 setWindowRole( "vlc-main" );
108 setWindowIcon( QApplication::windowIcon() );
109 setWindowOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
111 setAttribute( Qt::WA_MacBrushedMetal );
114 /* Is video in embedded in the UI or not */
115 b_videoEmbedded = var_InheritBool( p_intf, "embedded-video" );
117 /* Does the interface resize to video size or the opposite */
118 b_autoresize = var_InheritBool( p_intf, "qt-video-autoresize" );
120 /* Are we in the enhanced always-video mode or not ? */
121 b_minimalView = var_InheritBool( p_intf, "qt-minimal-view" );
123 /* Do we want anoying popups or not */
124 i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
127 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
129 /* Set the other interface settings */
130 settings = getSettings();
134 p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
138 b_plDocked = getSettings()->value( "MainWindow/pl-dock-status", true ).toBool();
141 /**************************
142 * UI and Widgets design
143 **************************/
144 setVLCWindowsTitle();
149 VLCMenuBar::createMenuBar( this, p_intf );
150 CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
151 this, destroyPopupMenu() );
153 createMainWidget( settings );
159 setStatusBarVisibility( getSettings()->value( "MainWindow/status-bar-visible", false ).toBool() );
161 /********************
163 ********************/
164 MainInputManager::getInstance( p_intf );
169 taskbar_wmsg = RegisterWindowMessage("TaskbarButtonCreated");
172 /*********************************
173 * Create the Systray Management *
174 *********************************/
177 /*************************************************************
178 * Connect the input manager to the GUI elements it manages *
179 * Beware initSystray did some connects on input manager too *
180 *************************************************************/
182 * Connects on nameChanged()
183 * Those connects are different because options can impeach them to trigger.
185 /* Main Interface statusbar */
186 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
187 this, setName( const QString& ) );
188 /* and title of the Main Interface*/
189 if( var_InheritBool( p_intf, "qt-name-in-title" ) )
191 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
192 this, setVLCWindowsTitle( const QString& ) );
194 /* END CONNECTS ON IM */
196 /* VideoWidget connects for asynchronous calls */
197 b_videoFullScreen = false;
198 connect( this, SIGNAL(askGetVideo(WId*,int*,int*,unsigned*,unsigned *)),
199 this, SLOT(getVideoSlot(WId*,int*,int*,unsigned*,unsigned*)),
200 Qt::BlockingQueuedConnection );
201 connect( this, SIGNAL(askReleaseVideo( void )),
202 this, SLOT(releaseVideoSlot( void )),
203 Qt::BlockingQueuedConnection );
204 CONNECT( this, askVideoOnTop(bool), this, setVideoOnTop(bool));
210 CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
211 this, setVideoSize( unsigned int, unsigned int ) );
212 CONNECT( videoWidget, sizeChanged( int, int ),
213 this, videoSizeChanged( int, int ) );
215 CONNECT( this, askVideoSetFullScreen( bool ),
216 this, setVideoFullScreen( bool ) );
219 CONNECT( THEDP, toolBarConfUpdated(), this, recreateToolbars() );
221 CONNECT( this, askToQuit(), THEDP, quit() );
223 CONNECT( this, askBoss(), this, setBoss() );
224 CONNECT( this, askRaise(), this, setRaise() );
226 /** END of CONNECTS**/
232 var_AddCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
233 var_AddCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
234 var_AddCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
236 /* Register callback for the intf-popupmenu variable */
237 var_AddCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
240 /* Final Sizing, restoration and placement of the interface */
241 if( settings->value( "MainWindow/playlist-visible", false ).toBool() )
244 QVLCTools::restoreWidgetPosition( settings, this, QSize(600, 420) );
246 b_interfaceFullScreen = isFullScreen();
248 setVisible( !b_hideAfterCreation );
250 computeMinimumSize();
252 /* Switch to minimal view if needed, must be called after the show() */
254 toggleMinimalView( true );
257 MainInterface::~MainInterface()
259 /* Unsure we hide the videoWidget before destroying it */
260 if( stackCentralOldWidget == videoWidget )
268 ImageList_Destroy( himl );
274 /* Be sure to kill the actionsManager... Only used in the MI and control */
275 ActionsManager::killInstance();
278 ExtensionsManager::killInstance();
280 /* Delete the FSC controller */
281 delete fullscreenControls;
285 settings->beginGroup("MainWindow");
286 settings->setValue( "pl-dock-status", b_plDocked );
287 /* Save playlist state */
289 settings->setValue( "playlist-visible", playlistVisible );
291 settings->setValue( "adv-controls",
292 getControlsVisibilityStatus() & CONTROLS_ADVANCED );
293 settings->setValue( "status-bar-visible", b_statusbarVisible );
295 /* Save the stackCentralW sizes */
296 settings->setValue( "bgSize", stackWidgetsSizes[bgWidget] );
297 settings->setValue( "playlistSize", stackWidgetsSizes[playlistWidget] );
298 settings->endGroup();
301 QVLCTools::saveWidgetPosition(settings, this);
303 /* Save undocked playlist size */
304 if( playlistWidget && !isPlDocked() )
305 QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
307 delete playlistWidget;
311 /* Unregister callbacks */
312 var_DelCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
313 var_DelCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
314 var_DelCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
315 var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
317 p_intf->p_sys->p_mi = NULL;
320 void MainInterface::computeMinimumSize()
323 if( menuBar()->isVisible() )
324 minWidth += __MAX( controls->sizeHint().width(), menuBar()->sizeHint().width() );
326 setMinimumWidth( minWidth );
329 /*****************************
331 *****************************/
332 void MainInterface::recreateToolbars()
334 bool b_adv = getControlsVisibilityStatus() & CONTROLS_ADVANCED;
339 controls = new ControlsWidget( p_intf, b_adv, this );
340 inputC = new InputControlsWidget( p_intf, this );
341 mainLayout->insertWidget( 2, inputC );
342 mainLayout->insertWidget( settings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
345 if( fullscreenControls )
347 delete fullscreenControls;
348 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
349 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
350 this, handleKeyPress( QKeyEvent * ) );
351 THEMIM->requestVoutUpdate();
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 bgWidget = new BackgroundWidget( p_intf );
383 stackCentralW->addWidget( bgWidget );
384 if ( !var_InheritBool( p_intf, "qt-bgcone" ) )
385 bgWidget->setWithArt( false );
387 if ( var_InheritBool( p_intf, "qt-bgcone-expands" ) )
388 bgWidget->setExpandstoHeight( true );
390 /* And video Outputs */
391 if( b_videoEmbedded )
393 videoWidget = new VideoWidget( p_intf );
394 stackCentralW->addWidget( videoWidget );
396 mainLayout->insertWidget( 1, stackCentralW );
398 stackWidgetsSizes[bgWidget] =
399 creationSettings->value( "MainWindow/bgSize", QSize( 600, 0 ) ).toSize();
400 /* Resize even if no-auto-resize, because we are at creation */
401 resizeStack( stackWidgetsSizes[bgWidget].width(), stackWidgetsSizes[bgWidget].height() );
403 /* Create the CONTROLS Widget */
404 controls = new ControlsWidget( p_intf,
405 creationSettings->value( "MainWindow/adv-controls", false ).toBool(), this );
406 inputC = new InputControlsWidget( p_intf, this );
408 mainLayout->insertWidget( 2, inputC );
409 mainLayout->insertWidget(
410 creationSettings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
413 /* Visualisation, disabled for now, they SUCK */
415 visualSelector = new VisualSelector( p_intf );
416 mainLayout->insertWidget( 0, visualSelector );
417 visualSelector->hide();
421 /* Enable the popup menu in the MI */
422 main->setContextMenuPolicy( Qt::CustomContextMenu );
423 CONNECT( main, customContextMenuRequested( const QPoint& ),
424 this, popupMenu( const QPoint& ) );
426 if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
427 /* Create the FULLSCREEN CONTROLS Widget */
428 if( var_InheritBool( p_intf, "qt-fs-controller" ) )
430 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
431 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
432 this, handleKeyPress( QKeyEvent * ) );
436 inline void MainInterface::initSystray()
438 bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
439 bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
441 if( var_InheritBool( p_intf, "qt-start-minimized") )
443 if( b_systrayAvailable )
445 b_systrayWanted = true;
446 b_hideAfterCreation = true;
449 msg_Err( p_intf, "cannot start minimized without system tray bar" );
452 if( b_systrayAvailable && b_systrayWanted )
456 inline void MainInterface::createStatusBar()
461 /* Widgets Creation*/
462 QStatusBar *statusBarr = statusBar();
464 TimeLabel *timeLabel = new TimeLabel( p_intf );
465 nameLabel = new ClickableQLabel();
466 nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
467 | Qt::TextSelectableByKeyboard );
468 SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
470 /* Styling those labels */
471 timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
472 speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
473 nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
474 timeLabel->setStyleSheet(
475 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
476 speedLabel->setStyleSheet(
477 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
478 /* pad both label and its tooltip */
479 nameLabel->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
481 /* and adding those */
482 statusBarr->addWidget( nameLabel, 8 );
483 statusBarr->addPermanentWidget( speedLabel, 0 );
484 statusBarr->addPermanentWidget( timeLabel, 0 );
486 CONNECT( nameLabel, doubleClicked(), THEDP, epgDialog() );
487 /* timeLabel behaviour:
488 - double clicking opens the goto time dialog
489 - right-clicking and clicking just toggle between remaining and
491 CONNECT( timeLabel, doubleClicked(), THEDP, gotoTimeDialog() );
493 CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
494 this, showCryptedLabel( bool ) );
496 CONNECT( THEMIM->getIM(), seekRequested( float ),
497 timeLabel, setDisplayPosition( float ) );
499 /* This shouldn't be necessary, but for somehow reason, the statusBarr
500 starts at height of 20px and when a text is shown it needs more space.
501 But, as the QMainWindow policy doesn't allow statusBar to change QMW's
502 geometry, we need to force a height. If you have a better idea, please
505 statusBarr->setFixedHeight( statusBarr->sizeHint().height() + 2 );
508 /**********************************************************************
509 * Handling of sizing of the components
510 **********************************************************************/
512 void MainInterface::debug()
515 msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
516 msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
517 msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
519 msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
520 msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
521 msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
525 inline void MainInterface::showVideo() { showTab( videoWidget ); }
526 inline void MainInterface::restoreStackOldWidget()
527 { showTab( stackCentralOldWidget ); }
529 inline void MainInterface::showTab( QWidget *widget )
532 if ( stackCentralOldWidget )
533 msg_Dbg( p_intf, "Old stackCentralOldWidget %s at index %i",
534 stackCentralOldWidget->metaObject()->className(),
535 stackCentralW->indexOf( stackCentralOldWidget ) );
536 msg_Dbg( p_intf, "ShowTab request for %s", widget->metaObject()->className() );
538 /* fixing when the playlist has been undocked after been hidden.
539 restoreStackOldWidget() is called when video stops but
540 stackCentralOldWidget would still be pointing to playlist */
541 if ( widget == playlistWidget && !isPlDocked() )
544 stackCentralOldWidget = stackCentralW->currentWidget();
545 stackWidgetsSizes[stackCentralOldWidget] = stackCentralW->size();
547 /* If we are playing video, embedded */
548 if( videoWidget && THEMIM->getIM()->hasVideo() )
550 /* Video -> Playlist */
551 if( videoWidget == stackCentralOldWidget && widget == playlistWidget )
553 stackCentralW->removeWidget( videoWidget );
554 videoWidget->show(); videoWidget->raise();
557 /* Playlist -> Video */
558 if( playlistWidget == stackCentralOldWidget && widget == videoWidget )
560 playlistWidget->artContainer->removeWidget( videoWidget );
561 videoWidget->show(); videoWidget->raise();
562 stackCentralW->addWidget( videoWidget );
565 /* Embedded playlist -> Non-embedded playlist */
566 if( bgWidget == stackCentralOldWidget && widget == videoWidget )
568 /* In rare case when video is started before the interface */
569 if( playlistWidget != NULL )
570 playlistWidget->artContainer->removeWidget( videoWidget );
571 videoWidget->show(); videoWidget->raise();
572 stackCentralW->addWidget( videoWidget );
573 stackCentralW->setCurrentWidget( videoWidget );
577 stackCentralW->setCurrentWidget( widget );
579 resizeStack( stackWidgetsSizes[widget].width(), stackWidgetsSizes[widget].height() );
582 msg_Dbg( p_intf, "Stack state changed to %s, index %i",
583 stackCentralW->currentWidget()->metaObject()->className(),
584 stackCentralW->currentIndex() );
585 msg_Dbg( p_intf, "New stackCentralOldWidget %s at index %i",
586 stackCentralOldWidget->metaObject()->className(),
587 stackCentralW->indexOf( stackCentralOldWidget ) );
590 /* This part is done later, to account for the new pl size */
591 if( videoWidget && THEMIM->getIM()->hasVideo() &&
592 videoWidget == stackCentralOldWidget && widget == playlistWidget )
594 playlistWidget->artContainer->addWidget( videoWidget );
595 playlistWidget->artContainer->setCurrentWidget( videoWidget );
599 void MainInterface::destroyPopupMenu()
601 VLCMenuBar::PopupMenu( p_intf, false );
604 void MainInterface::popupMenu( const QPoint & )
606 VLCMenuBar::PopupMenu( p_intf, true );
609 void MainInterface::toggleFSC()
611 if( !fullscreenControls ) return;
613 IMEvent *eShow = new IMEvent( FullscreenControlToggle_Type );
614 QApplication::postEvent( fullscreenControls, eShow );
617 /****************************************************************************
619 ****************************************************************************/
623 * You must not change the state of this object or other Qt4 UI objects,
624 * from the video output thread - only from the Qt4 UI main loop thread.
625 * All window provider queries must be handled through signals or events.
626 * That's why we have all those emit statements...
628 WId MainInterface::getVideo( int *pi_x, int *pi_y,
629 unsigned int *pi_width, unsigned int *pi_height )
634 /* This is a blocking call signal. Results are returned through pointers.
635 * Beware of deadlocks! */
637 emit askGetVideo( &id, pi_x, pi_y, pi_width, pi_height );
641 void MainInterface::getVideoSlot( WId *p_id, int *pi_x, int *pi_y,
642 unsigned *pi_width, unsigned *pi_height )
644 /* Hidden or minimized, activate */
645 if( isHidden() || isMinimized() )
646 toggleUpdateSystrayMenu();
648 /* Request the videoWidget */
649 WId ret = videoWidget->request( pi_x, pi_y,
650 pi_width, pi_height, !b_autoresize );
652 if( ret ) /* The videoWidget is available */
654 /* Consider the video active now */
657 /* Ask videoWidget to resize correctly, if we are in normal mode */
658 if( !isFullScreen() && !isMaximized() && b_autoresize )
659 videoWidget->SetSizing( *pi_width, *pi_height );
663 /* Asynchronous call from the WindowClose function */
664 void MainInterface::releaseVideo( void )
666 emit askReleaseVideo();
669 /* Function that is CONNECTED to the previous emit */
670 void MainInterface::releaseVideoSlot( void )
672 /* This function is called when the embedded video window is destroyed,
673 * or in the rare case that the embedded window is still here but the
674 * Qt4 interface exits. */
675 assert( videoWidget );
676 videoWidget->release();
677 setVideoOnTop( false );
678 setVideoFullScreen( false );
680 if( stackCentralW->currentWidget() == videoWidget )
681 restoreStackOldWidget();
682 else if( playlistWidget &&
683 playlistWidget->artContainer->currentWidget() == videoWidget )
685 playlistWidget->artContainer->setCurrentIndex( 0 );
686 stackCentralW->addWidget( videoWidget );
689 /* We don't want to have a blank video to popup */
690 stackCentralOldWidget = bgWidget;
693 void MainInterface::setVideoSize( unsigned int w, unsigned int h )
695 if( !isFullScreen() && !isMaximized() )
696 videoWidget->SetSizing( w, h );
699 void MainInterface::videoSizeChanged( int w, int h )
701 if( !playlistWidget || playlistWidget->artContainer->currentWidget() != videoWidget )
705 void MainInterface::setVideoFullScreen( bool fs )
707 b_videoFullScreen = fs;
710 int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
711 /* if user hasn't defined screennumber, or screennumber that is bigger
712 * than current number of screens, take screennumber where current interface
715 if( numscreen == -1 || numscreen > QApplication::desktop()->numScreens() )
716 numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
718 QRect screenres = QApplication::desktop()->screenGeometry( numscreen );
720 /* To be sure window is on proper-screen in xinerama */
721 if( !screenres.contains( pos() ) )
723 msg_Dbg( p_intf, "Moving video to correct screen");
724 move( QPoint( screenres.x(), screenres.y() ) );
728 if( playlistWidget != NULL && playlistWidget->artContainer->currentWidget() == videoWidget )
730 showTab( videoWidget );
734 setMinimalView( true );
735 setInterfaceFullScreen( true );
739 /* TODO do we want to restore screen and position ? (when
740 * qt-fullscreen-screennumber is forced) */
741 setMinimalView( b_minimalView );
742 setInterfaceFullScreen( b_interfaceFullScreen );
747 /* Slot to change the video always-on-top flag.
748 * Emit askVideoOnTop() to invoke this from other thread. */
749 void MainInterface::setVideoOnTop( bool on_top )
751 Qt::WindowFlags oldflags = windowFlags(), newflags;
754 newflags = oldflags | Qt::WindowStaysOnTopHint;
756 newflags = oldflags & ~Qt::WindowStaysOnTopHint;
757 if( newflags != oldflags && !b_videoFullScreen )
760 setWindowFlags( newflags );
761 show(); /* necessary to apply window flags */
765 /* Asynchronous call from WindowControl function */
766 int MainInterface::controlVideo( int i_query, va_list args )
770 case VOUT_WINDOW_SET_SIZE:
772 unsigned int i_width = va_arg( args, unsigned int );
773 unsigned int i_height = va_arg( args, unsigned int );
775 emit askVideoToResize( i_width, i_height );
778 case VOUT_WINDOW_SET_STATE:
780 unsigned i_arg = va_arg( args, unsigned );
781 unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
783 emit askVideoOnTop( on_top != 0 );
786 case VOUT_WINDOW_SET_FULLSCREEN:
788 bool b_fs = va_arg( args, int );
790 emit askVideoSetFullScreen( b_fs );
794 msg_Warn( p_intf, "unsupported control query" );
799 /*****************************************************************************
800 * Playlist, Visualisation and Menus handling
801 *****************************************************************************/
803 * Toggle the playlist widget or dialog
805 void MainInterface::createPlaylist()
807 playlistWidget = new PlaylistWidget( p_intf, this );
811 stackCentralW->addWidget( playlistWidget );
812 stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 600, 300 ) ).toSize();
817 playlistWidget->setParent( NULL );
819 playlistWidget->setWindowFlags( Qt::Window );
821 /* This will restore the geometry but will not work for position,
822 because of parenting */
823 QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
824 playlistWidget, QSize( 600, 300 ) );
828 void MainInterface::togglePlaylist()
830 if( !playlistWidget )
837 /* Playlist is not visible, show it */
838 if( stackCentralW->currentWidget() != playlistWidget )
840 if( stackCentralW->indexOf( playlistWidget ) == -1 )
841 stackCentralW->addWidget( playlistWidget );
842 showTab( playlistWidget );
846 restoreStackOldWidget();
848 playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
853 playlistWidget->setParent( NULL );
855 playlistWidget->setWindowFlags( Qt::Window );
856 playlistVisible = !playlistVisible;
857 playlistWidget->setVisible( playlistVisible );
862 void MainInterface::dockPlaylist( bool p_docked )
864 if( b_plDocked == p_docked ) return;
865 b_plDocked = p_docked;
867 if( !playlistWidget ) return; /* Playlist wasn't created yet */
868 if( !p_docked ) /* Previously docked */
870 /* If playlist is invisible don't show it */
871 if( stackCentralW->currentWidget() != playlistWidget ) return;
872 stackCentralW->removeWidget( playlistWidget );
874 playlistWidget->setParent( NULL );
876 playlistWidget->setWindowFlags( Qt::Window );
877 QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
878 playlistWidget, QSize( 600, 300 ) );
879 playlistWidget->show();
880 restoreStackOldWidget();
882 else /* Previously undocked */
884 QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
885 playlistWidget->setWindowFlags( Qt::Widget ); // Probably a Qt bug here
886 // It would be logical that QStackWidget::addWidget reset the flags...
887 stackCentralW->addWidget( playlistWidget );
889 /* If playlist is invisible don't show it */
890 if( !playlistWidget->isVisible() ) return;
891 showTab( playlistWidget );
893 playlistVisible = true;
897 * setMinimalView is the private function used by
898 * the SLOT toggleMinimalView and setVideoFullScreen
900 void MainInterface::setMinimalView( bool b_minimal )
902 menuBar()->setVisible( !b_minimal );
903 controls->setVisible( !b_minimal );
904 statusBar()->setVisible( !b_minimal && b_statusbarVisible );
905 inputC->setVisible( !b_minimal );
909 * This public SLOT is used for moving to minimal View Mode
911 * If b_minimal is false, then we are normalView
913 void MainInterface::toggleMinimalView( bool b_minimal )
915 if( !b_minimalView && b_autoresize ) /* Normal mode */
917 if( stackCentralW->currentWidget() == bgWidget )
919 if( stackCentralW->height() < 16 )
921 resizeStack( stackCentralW->width(), 100 );
925 b_minimalView = b_minimal;
926 if( !b_videoFullScreen )
928 setMinimalView( b_minimalView );
929 computeMinimumSize();
932 emit minimalViewToggled( b_minimalView );
935 /* toggling advanced controls buttons */
936 void MainInterface::toggleAdvancedButtons()
938 controls->toggleAdvanced();
939 // if( fullscreenControls ) fullscreenControls->toggleAdvanced();
942 /* Get the visibility status of the controls (hidden or not, advanced or not) */
943 int MainInterface::getControlsVisibilityStatus()
945 if( !controls ) return 0;
946 return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
947 + CONTROLS_ADVANCED * controls->b_advancedVisible );
950 void MainInterface::setStatusBarVisibility( bool b_visible )
952 statusBar()->setVisible( b_visible );
953 b_statusbarVisible = b_visible;
954 if( controls ) controls->setGripVisible( !b_statusbarVisible );
958 void MainInterface::visual()
960 if( !VISIBLE( visualSelector) )
962 visualSelector->show();
963 if( !THEMIM->getIM()->hasVideo() )
965 /* Show the background widget */
967 visualSelectorEnabled = true;
971 /* Stop any currently running visualization */
972 visualSelector->hide();
973 visualSelectorEnabled = false;
978 /************************************************************************
980 ************************************************************************/
981 void MainInterface::setName( const QString& name )
983 input_name = name; /* store it for the QSystray use */
984 /* Display it in the status bar, but also as a Tooltip in case it doesn't
986 nameLabel->setText( name );
987 nameLabel->setToolTip( name );
991 * Give the decorations of the Main Window a correct Name.
992 * If nothing is given, set it to VLC...
994 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
996 if( aTitle.isEmpty() )
998 setWindowTitle( qtr( "VLC media player" ) );
1002 setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
1006 void MainInterface::showCryptedLabel( bool b_show )
1008 if( cryptedLabel == NULL )
1010 cryptedLabel = new QLabel;
1011 // The lock icon is not the right one for DRM protection/scrambled.
1012 //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
1013 cryptedLabel->setText( "DRM" );
1014 statusBar()->addWidget( cryptedLabel );
1017 cryptedLabel->setVisible( b_show );
1020 void MainInterface::showBuffering( float f_cache )
1022 QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
1023 statusBar()->showMessage( amount, 1000 );
1026 /*****************************************************************************
1027 * Systray Icon and Systray Menu
1028 *****************************************************************************/
1030 * Create a SystemTray icon and a menu that would go with it.
1031 * Connects to a click handler on the icon.
1033 void MainInterface::createSystray()
1036 if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
1037 iconVLC = QIcon( ":/logo/vlc128-xmas.png" );
1039 iconVLC = QIcon( ":/logo/vlc128.png" );
1040 sysTray = new QSystemTrayIcon( iconVLC, this );
1041 sysTray->setToolTip( qtr( "VLC media player" ));
1043 systrayMenu = new QMenu( qtr( "VLC media player" ), this );
1044 systrayMenu->setIcon( iconVLC );
1046 VLCMenuBar::updateSystrayMenu( this, p_intf, true );
1049 CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
1050 this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
1052 /* Connects on nameChanged() */
1053 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
1054 this, updateSystrayTooltipName( const QString& ) );
1055 /* Connect PLAY_STATUS on the systray */
1056 CONNECT( THEMIM->getIM(), playingStatusChanged( int ),
1057 this, updateSystrayTooltipStatus( int ) );
1061 * Updates the Systray Icon's menu and toggle the main interface
1063 void MainInterface::toggleUpdateSystrayMenu()
1065 /* If hidden, show it */
1071 else if( isMinimized() )
1079 /* Visible (possibly under other windows) */
1081 /* check if any visible window is above vlc in the z-order,
1082 * but ignore the ones always on top
1083 * and the ones which can't be activated */
1086 wi.cbSize = sizeof( WINDOWINFO );
1087 for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
1088 hwnd && ( !IsWindowVisible( hwnd ) ||
1089 ( GetWindowInfo( hwnd, &wi ) &&
1090 (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
1091 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
1092 if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
1093 (wi.dwExStyle&WS_EX_TOPMOST) )
1106 VLCMenuBar::updateSystrayMenu( this, p_intf );
1109 /* First Item of the systray menu */
1110 void MainInterface::showUpdateSystrayMenu()
1118 VLCMenuBar::updateSystrayMenu( this, p_intf );
1121 /* First Item of the systray menu */
1122 void MainInterface::hideUpdateSystrayMenu()
1125 VLCMenuBar::updateSystrayMenu( this, p_intf );
1128 /* Click on systray Icon */
1129 void MainInterface::handleSystrayClick(
1130 QSystemTrayIcon::ActivationReason reason )
1134 case QSystemTrayIcon::Trigger:
1135 case QSystemTrayIcon::DoubleClick:
1137 VLCMenuBar::updateSystrayMenu( this, p_intf );
1139 toggleUpdateSystrayMenu();
1142 case QSystemTrayIcon::MiddleClick:
1143 sysTray->showMessage( qtr( "VLC media player" ),
1144 qtr( "Control menu for the player" ),
1145 QSystemTrayIcon::Information, 3000 );
1153 * Updates the name of the systray Icon tooltip.
1154 * Doesn't check if the systray exists, check before you call it.
1156 void MainInterface::updateSystrayTooltipName( const QString& name )
1158 if( name.isEmpty() )
1160 sysTray->setToolTip( qtr( "VLC media player" ) );
1164 sysTray->setToolTip( name );
1165 if( ( i_notificationSetting == NOTIFICATION_ALWAYS ) ||
1166 ( i_notificationSetting == NOTIFICATION_MINIMIZED && (isMinimized() || isHidden()) ) )
1168 sysTray->showMessage( qtr( "VLC media player" ), name,
1169 QSystemTrayIcon::NoIcon, 3000 );
1173 VLCMenuBar::updateSystrayMenu( this, p_intf );
1177 * Updates the status of the systray Icon tooltip.
1178 * Doesn't check if the systray exists, check before you call it.
1180 void MainInterface::updateSystrayTooltipStatus( int i_status )
1185 sysTray->setToolTip( input_name );
1188 sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1191 sysTray->setToolTip( qtr( "VLC media player" ) );
1194 VLCMenuBar::updateSystrayMenu( this, p_intf );
1197 void MainInterface::changeEvent(QEvent *event)
1199 if( event->type() == QEvent::WindowStateChange )
1201 QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
1202 Qt::WindowStates newState = windowState();
1203 Qt::WindowStates oldState = windowStateChangeEvent->oldState();
1205 if( newState & Qt::WindowMinimized )
1207 b_hasPausedWhenMinimized = false;
1209 if( THEMIM->getIM()->playingStatus() == PLAYING_S &&
1210 THEMIM->getIM()->hasVideo() && !THEMIM->getIM()->hasVisualisation() &&
1213 b_hasPausedWhenMinimized = true;
1217 else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
1219 if( b_hasPausedWhenMinimized )
1226 QWidget::changeEvent(event);
1229 /************************************************************************
1231 ************************************************************************/
1232 void MainInterface::dropEvent(QDropEvent *event)
1234 dropEventPlay( event, true );
1240 * Event called if something is dropped onto a VLC window
1241 * \param event the event in question
1242 * \param b_play whether to play the file immediately
1243 * \param b_playlist true to add to playlist, false to add to media library
1246 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play, bool b_playlist )
1248 if( event->possibleActions() & ( Qt::CopyAction | Qt::MoveAction ) )
1249 event->setDropAction( Qt::CopyAction );
1253 const QMimeData *mimeData = event->mimeData();
1255 /* D&D of a subtitles file, add it on the fly */
1256 if( mimeData->urls().count() == 1 && THEMIM->getIM()->hasInput() )
1258 if( !input_AddSubtitle( THEMIM->getInput(),
1259 qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1267 bool first = b_play;
1268 foreach( const QUrl &url, mimeData->urls() )
1272 QString mrl = toURI( url.toEncoded().constData() );
1273 playlist_Add( THEPL, qtu(mrl), NULL,
1274 PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1275 PLAYLIST_END, b_playlist, pl_Unlocked );
1277 RecentsMRL::getInstance( p_intf )->addRecent( mrl );
1281 /* Browsers give content as text if you dnd the addressbar,
1282 so check if mimedata has valid url in text and use it
1283 if we didn't get any normal Urls()*/
1284 if( !mimeData->hasUrls() && mimeData->hasText() &&
1285 QUrl(mimeData->text()).isValid() )
1287 QString mrl = toURI( mimeData->text() );
1288 playlist_Add( THEPL, qtu(mrl), NULL,
1289 PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1290 PLAYLIST_END, b_playlist, pl_Unlocked );
1294 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1296 event->acceptProposedAction();
1298 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1300 event->acceptProposedAction();
1302 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1307 /************************************************************************
1309 ************************************************************************/
1310 void MainInterface::keyPressEvent( QKeyEvent *e )
1312 handleKeyPress( e );
1315 void MainInterface::handleKeyPress( QKeyEvent *e )
1317 if( ( ( e->modifiers() & Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) ) ||
1318 ( b_minimalView && !b_videoFullScreen && e->key() == Qt::Key_Escape ) )
1320 toggleMinimalView( !b_minimalView );
1324 int i_vlck = qtEventToVLCKey( e );
1327 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1334 void MainInterface::wheelEvent( QWheelEvent *e )
1336 int i_vlckey = qtWheelEventToVLCKey( e );
1337 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1341 void MainInterface::closeEvent( QCloseEvent *e )
1344 emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
1345 /* Accept session quit. Otherwise we break the desktop mamager. */
1349 void MainInterface::setInterfaceFullScreen( bool fs )
1352 setWindowState( windowState() | Qt::WindowFullScreen );
1354 setWindowState( windowState() & ~Qt::WindowFullScreen );
1356 void MainInterface::toggleInterfaceFullScreen()
1358 b_interfaceFullScreen = !b_interfaceFullScreen;
1359 if( !b_videoFullScreen )
1360 setInterfaceFullScreen( b_interfaceFullScreen );
1361 emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1364 void MainInterface::emitBoss()
1368 void MainInterface::setBoss()
1381 void MainInterface::emitRaise()
1385 void MainInterface::setRaise()
1391 /*****************************************************************************
1392 * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1393 * We don't show the menu directly here because we don't want the
1394 * caller to block for a too long time.
1395 *****************************************************************************/
1396 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1397 vlc_value_t old_val, vlc_value_t new_val, void *param )
1399 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1401 intf_thread_t *p_intf = (intf_thread_t *)param;
1403 if( p_intf->pf_show_dialog )
1405 p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1406 new_val.b_bool, NULL );
1412 /*****************************************************************************
1413 * IntfShowCB: callback triggered by the intf-toggle-fscontrol libvlc variable.
1414 *****************************************************************************/
1415 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1416 vlc_value_t old_val, vlc_value_t new_val, void *param )
1418 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1419 VLC_UNUSED( new_val );
1421 intf_thread_t *p_intf = (intf_thread_t *)param;
1422 p_intf->p_sys->p_mi->toggleFSC();
1428 /*****************************************************************************
1429 * IntfRaiseMainCB: callback triggered by the intf-show-main libvlc variable.
1430 *****************************************************************************/
1431 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
1432 vlc_value_t old_val, vlc_value_t new_val, void *param )
1434 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1435 VLC_UNUSED( new_val );
1437 intf_thread_t *p_intf = (intf_thread_t *)param;
1438 p_intf->p_sys->p_mi->emitRaise();
1443 /*****************************************************************************
1444 * IntfBossCB: callback triggered by the intf-boss libvlc variable.
1445 *****************************************************************************/
1446 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
1447 vlc_value_t old_val, vlc_value_t new_val, void *param )
1449 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1450 VLC_UNUSED( new_val );
1452 intf_thread_t *p_intf = (intf_thread_t *)param;
1453 p_intf->p_sys->p_mi->emitBoss();