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
44 #include "dialogs/playlist.hpp" // PlaylistDialog
46 #include "menus.hpp" // Menu creation
47 #include "recents.hpp" // RecentItems when DnD
49 #include <QCloseEvent>
60 #include <QStackedWidget>
62 #include <vlc_keys.h> /* Wheel event */
63 #include <vlc_vout_display.h> /* vout_thread_t and VOUT_ events */
67 /* Callback prototypes */
68 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
69 vlc_value_t old_val, vlc_value_t new_val, void *param );
70 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
71 vlc_value_t old_val, vlc_value_t new_val, void *param );
72 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
73 vlc_value_t old_val, vlc_value_t new_val, void *param );
74 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
75 vlc_value_t old_val, vlc_value_t new_val,
78 MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
80 /* Variables initialisation */
83 playlistWidget = NULL;
84 stackCentralOldWidget= NULL;
86 fullscreenControls = NULL;
91 b_hideAfterCreation = false; // --qt-start-minimized
92 playlistVisible = false;
94 b_interfaceFullScreen= false;
95 b_hasPausedWhenMinimized = false;
99 FirstRun::CheckAndRun( this, p_intf );
102 * Configuration and settings
103 * Pre-building of interface
106 setFocusPolicy( Qt::StrongFocus );
107 setAcceptDrops( true );
108 setWindowRole( "vlc-main" );
109 setWindowIcon( QApplication::windowIcon() );
110 setWindowOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
112 setAttribute( Qt::WA_MacBrushedMetal );
115 /* Is video in embedded in the UI or not */
116 b_videoEmbedded = var_InheritBool( p_intf, "embedded-video" );
118 /* Does the interface resize to video size or the opposite */
119 b_autoresize = var_InheritBool( p_intf, "qt-video-autoresize" );
121 /* Are we in the enhanced always-video mode or not ? */
122 b_minimalView = var_InheritBool( p_intf, "qt-minimal-view" );
124 /* Do we want anoying popups or not */
125 i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
128 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
130 /* Set the other interface settings */
131 settings = getSettings();
135 p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
139 b_plDocked = getSettings()->value( "MainWindow/pl-dock-status", true ).toBool();
142 /**************************
143 * UI and Widgets design
144 **************************/
145 setVLCWindowsTitle();
150 VLCMenuBar::createMenuBar( this, p_intf );
151 CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
152 this, destroyPopupMenu() );
154 createMainWidget( settings );
160 setStatusBarVisibility( getSettings()->value( "MainWindow/status-bar-visible", false ).toBool() );
162 /********************
164 ********************/
165 MainInputManager::getInstance( p_intf );
170 taskbar_wmsg = RegisterWindowMessage("TaskbarButtonCreated");
173 /*********************************
174 * Create the Systray Management *
175 *********************************/
178 /*************************************************************
179 * Connect the input manager to the GUI elements it manages *
180 * Beware initSystray did some connects on input manager too *
181 *************************************************************/
183 * Connects on nameChanged()
184 * Those connects are different because options can impeach them to trigger.
186 /* Main Interface statusbar */
187 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
188 this, setName( const QString& ) );
189 /* and title of the Main Interface*/
190 if( var_InheritBool( p_intf, "qt-name-in-title" ) )
192 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
193 this, setVLCWindowsTitle( const QString& ) );
195 /* END CONNECTS ON IM */
197 /* VideoWidget connects for asynchronous calls */
198 b_videoFullScreen = false;
199 connect( this, SIGNAL(askGetVideo(WId*,int*,int*,unsigned*,unsigned *)),
200 this, SLOT(getVideoSlot(WId*,int*,int*,unsigned*,unsigned*)),
201 Qt::BlockingQueuedConnection );
202 connect( this, SIGNAL(askReleaseVideo( void )),
203 this, SLOT(releaseVideoSlot( void )),
204 Qt::BlockingQueuedConnection );
205 CONNECT( this, askVideoOnTop(bool), this, setVideoOnTop(bool));
211 CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
212 this, setVideoSize( unsigned int, unsigned int ) );
213 CONNECT( videoWidget, sizeChanged( int, int ),
214 this, videoSizeChanged( int, int ) );
216 CONNECT( this, askVideoSetFullScreen( bool ),
217 this, setVideoFullScreen( bool ) );
220 CONNECT( THEDP, toolBarConfUpdated(), this, recreateToolbars() );
222 CONNECT( this, askToQuit(), THEDP, quit() );
224 CONNECT( this, askBoss(), this, setBoss() );
225 CONNECT( this, askRaise(), this, setRaise() );
227 /** END of CONNECTS**/
233 var_AddCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
234 var_AddCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
235 var_AddCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
237 /* Register callback for the intf-popupmenu variable */
238 var_AddCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
241 /* Final Sizing, restoration and placement of the interface */
242 if( settings->value( "MainWindow/playlist-visible", false ).toBool() )
245 QVLCTools::restoreWidgetPosition( settings, this, QSize(600, 420) );
247 b_interfaceFullScreen = isFullScreen();
249 setVisible( !b_hideAfterCreation );
251 computeMinimumSize();
253 /* Switch to minimal view if needed, must be called after the show() */
255 toggleMinimalView( true );
258 MainInterface::~MainInterface()
260 /* Unsure we hide the videoWidget before destroying it */
261 if( stackCentralOldWidget == videoWidget )
269 ImageList_Destroy( himl );
275 /* Be sure to kill the actionsManager... Only used in the MI and control */
276 ActionsManager::killInstance();
279 ExtensionsManager::killInstance();
281 /* Delete the FSC controller */
282 delete fullscreenControls;
286 settings->beginGroup("MainWindow");
287 settings->setValue( "pl-dock-status", b_plDocked );
289 /* Save playlist state */
290 settings->setValue( "playlist-visible", playlistVisible );
292 settings->setValue( "adv-controls",
293 getControlsVisibilityStatus() & CONTROLS_ADVANCED );
294 settings->setValue( "status-bar-visible", b_statusbarVisible );
296 /* Save the stackCentralW sizes */
297 settings->setValue( "bgSize", stackWidgetsSizes[bgWidget] );
298 settings->setValue( "playlistSize", stackWidgetsSizes[playlistWidget] );
299 settings->endGroup();
302 QVLCTools::saveWidgetPosition(settings, this);
306 /* Unregister callbacks */
307 var_DelCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
308 var_DelCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
309 var_DelCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
310 var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
312 p_intf->p_sys->p_mi = NULL;
315 void MainInterface::computeMinimumSize()
318 if( menuBar()->isVisible() )
319 minWidth += __MAX( controls->sizeHint().width(), menuBar()->sizeHint().width() );
321 setMinimumWidth( minWidth );
324 /*****************************
326 *****************************/
327 void MainInterface::recreateToolbars()
329 bool b_adv = getControlsVisibilityStatus() & CONTROLS_ADVANCED;
334 controls = new ControlsWidget( p_intf, b_adv, this );
335 inputC = new InputControlsWidget( p_intf, this );
336 mainLayout->insertWidget( 2, inputC );
337 mainLayout->insertWidget( settings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
340 if( fullscreenControls )
342 delete fullscreenControls;
343 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
344 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
345 this, handleKeyPress( QKeyEvent * ) );
346 THEMIM->requestVoutUpdate();
350 void MainInterface::reloadPrefs()
352 i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
353 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
355 p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
357 if( !var_InheritBool( p_intf, "qt-fs-controller" ) && fullscreenControls )
359 delete fullscreenControls;
360 fullscreenControls = NULL;
364 void MainInterface::createMainWidget( QSettings *creationSettings )
366 /* Create the main Widget and the mainLayout */
367 QWidget *main = new QWidget;
368 setCentralWidget( main );
369 mainLayout = new QVBoxLayout( main );
370 main->setContentsMargins( 0, 0, 0, 0 );
371 mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
374 stackCentralW = new QVLCStackedWidget( main );
377 bgWidget = new BackgroundWidget( p_intf );
378 stackCentralW->addWidget( bgWidget );
379 if ( !var_InheritBool( p_intf, "qt-bgcone" ) )
380 bgWidget->setWithArt( false );
382 if ( var_InheritBool( p_intf, "qt-bgcone-expands" ) )
383 bgWidget->setExpandstoHeight( true );
385 /* And video Outputs */
386 if( b_videoEmbedded )
388 videoWidget = new VideoWidget( p_intf );
389 stackCentralW->addWidget( videoWidget );
391 mainLayout->insertWidget( 1, stackCentralW );
393 stackWidgetsSizes[bgWidget] =
394 creationSettings->value( "MainWindow/bgSize", QSize( 600, 0 ) ).toSize();
395 /* Resize even if no-auto-resize, because we are at creation */
396 resizeStack( stackWidgetsSizes[bgWidget].width(), stackWidgetsSizes[bgWidget].height() );
398 /* Create the CONTROLS Widget */
399 controls = new ControlsWidget( p_intf,
400 creationSettings->value( "MainWindow/adv-controls", false ).toBool(), this );
401 inputC = new InputControlsWidget( p_intf, this );
403 mainLayout->insertWidget( 2, inputC );
404 mainLayout->insertWidget(
405 creationSettings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
408 /* Visualisation, disabled for now, they SUCK */
410 visualSelector = new VisualSelector( p_intf );
411 mainLayout->insertWidget( 0, visualSelector );
412 visualSelector->hide();
416 /* Enable the popup menu in the MI */
417 main->setContextMenuPolicy( Qt::CustomContextMenu );
418 CONNECT( main, customContextMenuRequested( const QPoint& ),
419 this, popupMenu( const QPoint& ) );
421 if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
422 /* Create the FULLSCREEN CONTROLS Widget */
423 if( var_InheritBool( p_intf, "qt-fs-controller" ) )
425 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
426 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
427 this, handleKeyPress( QKeyEvent * ) );
431 inline void MainInterface::initSystray()
433 bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
434 bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
436 if( var_InheritBool( p_intf, "qt-start-minimized") )
438 if( b_systrayAvailable )
440 b_systrayWanted = true;
441 b_hideAfterCreation = true;
444 msg_Err( p_intf, "cannot start minimized without system tray bar" );
447 if( b_systrayAvailable && b_systrayWanted )
451 inline void MainInterface::createStatusBar()
456 /* Widgets Creation*/
457 QStatusBar *statusBarr = statusBar();
459 TimeLabel *timeLabel = new TimeLabel( p_intf );
460 nameLabel = new ClickableQLabel();
461 nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
462 | Qt::TextSelectableByKeyboard );
463 SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
465 /* Styling those labels */
466 timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
467 speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
468 nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
469 timeLabel->setStyleSheet(
470 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
471 speedLabel->setStyleSheet(
472 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
473 /* pad both label and its tooltip */
474 nameLabel->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
476 /* and adding those */
477 statusBarr->addWidget( nameLabel, 8 );
478 statusBarr->addPermanentWidget( speedLabel, 0 );
479 statusBarr->addPermanentWidget( timeLabel, 0 );
481 CONNECT( nameLabel, doubleClicked(), THEDP, epgDialog() );
482 /* timeLabel behaviour:
483 - double clicking opens the goto time dialog
484 - right-clicking and clicking just toggle between remaining and
486 CONNECT( timeLabel, doubleClicked(), THEDP, gotoTimeDialog() );
488 CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
489 this, showCryptedLabel( bool ) );
491 CONNECT( THEMIM->getIM(), seekRequested( float ),
492 timeLabel, setDisplayPosition( float ) );
494 /* This shouldn't be necessary, but for somehow reason, the statusBarr
495 starts at height of 20px and when a text is shown it needs more space.
496 But, as the QMainWindow policy doesn't allow statusBar to change QMW's
497 geometry, we need to force a height. If you have a better idea, please
500 statusBarr->setFixedHeight( statusBarr->sizeHint().height() + 2 );
503 /**********************************************************************
504 * Handling of sizing of the components
505 **********************************************************************/
507 void MainInterface::debug()
510 msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
511 msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
512 msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
514 msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
515 msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
516 msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
520 inline void MainInterface::showVideo() { showTab( videoWidget ); }
521 inline void MainInterface::restoreStackOldWidget()
522 { showTab( stackCentralOldWidget ); }
524 inline void MainInterface::showTab( QWidget *widget )
526 if ( !widget ) widget = bgWidget; /* trying to restore a null oldwidget */
528 if ( stackCentralOldWidget )
529 msg_Dbg( p_intf, "Old stackCentralOldWidget %s at index %i",
530 stackCentralOldWidget->metaObject()->className(),
531 stackCentralW->indexOf( stackCentralOldWidget ) );
532 msg_Dbg( p_intf, "ShowTab request for %s", widget->metaObject()->className() );
534 /* fixing when the playlist has been undocked after being hidden.
535 restoreStackOldWidget() is called when video stops but
536 stackCentralOldWidget would still be pointing to playlist */
537 if ( widget == playlistWidget && !isPlDocked() )
540 stackCentralOldWidget = stackCentralW->currentWidget();
541 stackWidgetsSizes[stackCentralOldWidget] = stackCentralW->size();
543 /* If we are playing video, embedded */
544 if( videoWidget && THEMIM->getIM()->hasVideo() )
546 /* Video -> Playlist */
547 if( videoWidget == stackCentralOldWidget && widget == playlistWidget )
549 stackCentralW->removeWidget( videoWidget );
550 videoWidget->show(); videoWidget->raise();
553 /* Playlist -> Video */
554 if( playlistWidget == stackCentralOldWidget && widget == videoWidget )
556 playlistWidget->artContainer->removeWidget( videoWidget );
557 videoWidget->show(); videoWidget->raise();
558 stackCentralW->addWidget( videoWidget );
561 /* Embedded playlist -> Non-embedded playlist */
562 if( bgWidget == stackCentralOldWidget && widget == videoWidget )
564 /* In rare case when video is started before the interface */
565 if( playlistWidget != NULL )
566 playlistWidget->artContainer->removeWidget( videoWidget );
567 videoWidget->show(); videoWidget->raise();
568 stackCentralW->addWidget( videoWidget );
569 stackCentralW->setCurrentWidget( videoWidget );
573 stackCentralW->setCurrentWidget( widget );
575 resizeStack( stackWidgetsSizes[widget].width(), stackWidgetsSizes[widget].height() );
578 msg_Dbg( p_intf, "Stack state changed to %s, index %i",
579 stackCentralW->currentWidget()->metaObject()->className(),
580 stackCentralW->currentIndex() );
581 msg_Dbg( p_intf, "New stackCentralOldWidget %s at index %i",
582 stackCentralOldWidget->metaObject()->className(),
583 stackCentralW->indexOf( stackCentralOldWidget ) );
586 /* This part is done later, to account for the new pl size */
587 if( videoWidget && THEMIM->getIM()->hasVideo() &&
588 videoWidget == stackCentralOldWidget && widget == playlistWidget )
590 playlistWidget->artContainer->addWidget( videoWidget );
591 playlistWidget->artContainer->setCurrentWidget( videoWidget );
595 void MainInterface::destroyPopupMenu()
597 VLCMenuBar::PopupMenu( p_intf, false );
600 void MainInterface::popupMenu( const QPoint & )
602 VLCMenuBar::PopupMenu( p_intf, true );
605 void MainInterface::toggleFSC()
607 if( !fullscreenControls ) return;
609 IMEvent *eShow = new IMEvent( FullscreenControlToggle_Type );
610 QApplication::postEvent( fullscreenControls, eShow );
613 /****************************************************************************
615 ****************************************************************************/
619 * You must not change the state of this object or other Qt4 UI objects,
620 * from the video output thread - only from the Qt4 UI main loop thread.
621 * All window provider queries must be handled through signals or events.
622 * That's why we have all those emit statements...
624 WId MainInterface::getVideo( int *pi_x, int *pi_y,
625 unsigned int *pi_width, unsigned int *pi_height )
630 /* This is a blocking call signal. Results are returned through pointers.
631 * Beware of deadlocks! */
633 emit askGetVideo( &id, pi_x, pi_y, pi_width, pi_height );
637 void MainInterface::getVideoSlot( WId *p_id, int *pi_x, int *pi_y,
638 unsigned *pi_width, unsigned *pi_height )
640 /* Hidden or minimized, activate */
641 if( isHidden() || isMinimized() )
642 toggleUpdateSystrayMenu();
644 /* Request the videoWidget */
645 WId ret = videoWidget->request( pi_x, pi_y,
646 pi_width, pi_height, !b_autoresize );
648 if( ret ) /* The videoWidget is available */
650 /* Consider the video active now */
653 /* Ask videoWidget to resize correctly, if we are in normal mode */
654 if( !isFullScreen() && !isMaximized() && b_autoresize )
655 videoWidget->SetSizing( *pi_width, *pi_height );
659 /* Asynchronous call from the WindowClose function */
660 void MainInterface::releaseVideo( void )
662 emit askReleaseVideo();
665 /* Function that is CONNECTED to the previous emit */
666 void MainInterface::releaseVideoSlot( void )
668 /* This function is called when the embedded video window is destroyed,
669 * or in the rare case that the embedded window is still here but the
670 * Qt4 interface exits. */
671 assert( videoWidget );
672 videoWidget->release();
673 setVideoOnTop( false );
674 setVideoFullScreen( false );
676 if( stackCentralW->currentWidget() == videoWidget )
677 restoreStackOldWidget();
678 else if( playlistWidget &&
679 playlistWidget->artContainer->currentWidget() == videoWidget )
681 playlistWidget->artContainer->setCurrentIndex( 0 );
682 stackCentralW->addWidget( videoWidget );
685 /* We don't want to have a blank video to popup */
686 stackCentralOldWidget = bgWidget;
689 void MainInterface::setVideoSize( unsigned int w, unsigned int h )
691 if( !isFullScreen() && !isMaximized() )
692 videoWidget->SetSizing( w, h );
695 void MainInterface::videoSizeChanged( int w, int h )
697 if( !playlistWidget || playlistWidget->artContainer->currentWidget() != videoWidget )
701 void MainInterface::setVideoFullScreen( bool fs )
703 b_videoFullScreen = fs;
706 int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
707 /* if user hasn't defined screennumber, or screennumber that is bigger
708 * than current number of screens, take screennumber where current interface
711 if( numscreen == -1 || numscreen > QApplication::desktop()->numScreens() )
712 numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
714 QRect screenres = QApplication::desktop()->screenGeometry( numscreen );
716 /* To be sure window is on proper-screen in xinerama */
717 if( !screenres.contains( pos() ) )
719 msg_Dbg( p_intf, "Moving video to correct screen");
720 move( QPoint( screenres.x(), screenres.y() ) );
724 if( playlistWidget != NULL && playlistWidget->artContainer->currentWidget() == videoWidget )
726 showTab( videoWidget );
730 setMinimalView( true );
731 setInterfaceFullScreen( true );
735 /* TODO do we want to restore screen and position ? (when
736 * qt-fullscreen-screennumber is forced) */
737 setMinimalView( b_minimalView );
738 setInterfaceFullScreen( b_interfaceFullScreen );
743 /* Slot to change the video always-on-top flag.
744 * Emit askVideoOnTop() to invoke this from other thread. */
745 void MainInterface::setVideoOnTop( bool on_top )
747 Qt::WindowFlags oldflags = windowFlags(), newflags;
750 newflags = oldflags | Qt::WindowStaysOnTopHint;
752 newflags = oldflags & ~Qt::WindowStaysOnTopHint;
753 if( newflags != oldflags && !b_videoFullScreen )
756 setWindowFlags( newflags );
757 show(); /* necessary to apply window flags */
761 /* Asynchronous call from WindowControl function */
762 int MainInterface::controlVideo( int i_query, va_list args )
766 case VOUT_WINDOW_SET_SIZE:
768 unsigned int i_width = va_arg( args, unsigned int );
769 unsigned int i_height = va_arg( args, unsigned int );
771 emit askVideoToResize( i_width, i_height );
774 case VOUT_WINDOW_SET_STATE:
776 unsigned i_arg = va_arg( args, unsigned );
777 unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
779 emit askVideoOnTop( on_top != 0 );
782 case VOUT_WINDOW_SET_FULLSCREEN:
784 bool b_fs = va_arg( args, int );
786 emit askVideoSetFullScreen( b_fs );
790 msg_Warn( p_intf, "unsupported control query" );
795 /*****************************************************************************
796 * Playlist, Visualisation and Menus handling
797 *****************************************************************************/
799 * Toggle the playlist widget or dialog
801 void MainInterface::createPlaylist()
803 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
807 playlistWidget = dialog->exportPlaylistWidget();
808 stackCentralW->addWidget( playlistWidget );
809 stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 600, 300 ) ).toSize();
811 CONNECT( dialog, visibilityChanged(bool), this, setPlaylistVisibility(bool) );
814 void MainInterface::togglePlaylist()
816 if( !playlistWidget ) createPlaylist();
818 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
821 if ( dialog->hasPlaylistWidget() )
822 playlistWidget = dialog->exportPlaylistWidget();
823 /* Playlist is not visible, show it */
824 if( stackCentralW->currentWidget() != playlistWidget )
826 if( stackCentralW->indexOf( playlistWidget ) == -1 )
827 stackCentralW->addWidget( playlistWidget );
828 showTab( playlistWidget );
832 restoreStackOldWidget();
834 playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
838 playlistVisible = !playlistVisible;
839 if ( ! dialog->hasPlaylistWidget() )
840 dialog->importPlaylistWidget( playlistWidget );
841 if ( playlistVisible )
849 void MainInterface::dockPlaylist( bool p_docked )
851 if( b_plDocked == p_docked ) return;
852 /* some extra check */
853 if ( b_plDocked && !playlistWidget ) createPlaylist();
855 b_plDocked = p_docked;
856 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
858 if( !p_docked ) /* Previously docked */
860 playlistVisible = playlistWidget->isVisible();
861 stackCentralW->removeWidget( playlistWidget );
862 dialog->importPlaylistWidget( playlistWidget );
863 if ( playlistVisible ) dialog->show();
864 restoreStackOldWidget();
866 else /* Previously undocked */
868 playlistVisible = dialog->isVisible();
870 playlistWidget = dialog->exportPlaylistWidget();
871 stackCentralW->addWidget( playlistWidget );
873 /* If playlist is invisible don't show it */
874 if( playlistVisible ) showTab( playlistWidget );
879 * setMinimalView is the private function used by
880 * the SLOT toggleMinimalView and setVideoFullScreen
882 void MainInterface::setMinimalView( bool b_minimal )
884 menuBar()->setVisible( !b_minimal );
885 controls->setVisible( !b_minimal );
886 statusBar()->setVisible( !b_minimal && b_statusbarVisible );
887 inputC->setVisible( !b_minimal );
891 * This public SLOT is used for moving to minimal View Mode
893 * If b_minimal is false, then we are normalView
895 void MainInterface::toggleMinimalView( bool b_minimal )
897 if( !b_minimalView && b_autoresize ) /* Normal mode */
899 if( stackCentralW->currentWidget() == bgWidget )
901 if( stackCentralW->height() < 16 )
903 resizeStack( stackCentralW->width(), 100 );
907 b_minimalView = b_minimal;
908 if( !b_videoFullScreen )
910 setMinimalView( b_minimalView );
911 computeMinimumSize();
914 emit minimalViewToggled( b_minimalView );
917 /* toggling advanced controls buttons */
918 void MainInterface::toggleAdvancedButtons()
920 controls->toggleAdvanced();
921 // if( fullscreenControls ) fullscreenControls->toggleAdvanced();
924 /* Get the visibility status of the controls (hidden or not, advanced or not) */
925 int MainInterface::getControlsVisibilityStatus()
927 if( !controls ) return 0;
928 return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
929 + CONTROLS_ADVANCED * controls->b_advancedVisible );
932 void MainInterface::setStatusBarVisibility( bool b_visible )
934 statusBar()->setVisible( b_visible );
935 b_statusbarVisible = b_visible;
936 if( controls ) controls->setGripVisible( !b_statusbarVisible );
940 void MainInterface::setPlaylistVisibility( bool b_visible )
943 playlistVisible = b_visible;
947 void MainInterface::visual()
949 if( !VISIBLE( visualSelector) )
951 visualSelector->show();
952 if( !THEMIM->getIM()->hasVideo() )
954 /* Show the background widget */
956 visualSelectorEnabled = true;
960 /* Stop any currently running visualization */
961 visualSelector->hide();
962 visualSelectorEnabled = false;
967 /************************************************************************
969 ************************************************************************/
970 void MainInterface::setName( const QString& name )
972 input_name = name; /* store it for the QSystray use */
973 /* Display it in the status bar, but also as a Tooltip in case it doesn't
975 nameLabel->setText( name );
976 nameLabel->setToolTip( name );
980 * Give the decorations of the Main Window a correct Name.
981 * If nothing is given, set it to VLC...
983 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
985 if( aTitle.isEmpty() )
987 setWindowTitle( qtr( "VLC media player" ) );
991 setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
995 void MainInterface::showCryptedLabel( bool b_show )
997 if( cryptedLabel == NULL )
999 cryptedLabel = new QLabel;
1000 // The lock icon is not the right one for DRM protection/scrambled.
1001 //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
1002 cryptedLabel->setText( "DRM" );
1003 statusBar()->addWidget( cryptedLabel );
1006 cryptedLabel->setVisible( b_show );
1009 void MainInterface::showBuffering( float f_cache )
1011 QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
1012 statusBar()->showMessage( amount, 1000 );
1015 /*****************************************************************************
1016 * Systray Icon and Systray Menu
1017 *****************************************************************************/
1019 * Create a SystemTray icon and a menu that would go with it.
1020 * Connects to a click handler on the icon.
1022 void MainInterface::createSystray()
1025 if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
1026 iconVLC = QIcon( ":/logo/vlc128-xmas.png" );
1028 iconVLC = QIcon( ":/logo/vlc128.png" );
1029 sysTray = new QSystemTrayIcon( iconVLC, this );
1030 sysTray->setToolTip( qtr( "VLC media player" ));
1032 systrayMenu = new QMenu( qtr( "VLC media player" ), this );
1033 systrayMenu->setIcon( iconVLC );
1035 VLCMenuBar::updateSystrayMenu( this, p_intf, true );
1038 CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
1039 this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
1041 /* Connects on nameChanged() */
1042 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
1043 this, updateSystrayTooltipName( const QString& ) );
1044 /* Connect PLAY_STATUS on the systray */
1045 CONNECT( THEMIM->getIM(), playingStatusChanged( int ),
1046 this, updateSystrayTooltipStatus( int ) );
1050 * Updates the Systray Icon's menu and toggle the main interface
1052 void MainInterface::toggleUpdateSystrayMenu()
1054 /* If hidden, show it */
1060 else if( isMinimized() )
1068 /* Visible (possibly under other windows) */
1070 /* check if any visible window is above vlc in the z-order,
1071 * but ignore the ones always on top
1072 * and the ones which can't be activated */
1075 wi.cbSize = sizeof( WINDOWINFO );
1076 for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
1077 hwnd && ( !IsWindowVisible( hwnd ) ||
1078 ( GetWindowInfo( hwnd, &wi ) &&
1079 (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
1080 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
1081 if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
1082 (wi.dwExStyle&WS_EX_TOPMOST) )
1095 VLCMenuBar::updateSystrayMenu( this, p_intf );
1098 /* First Item of the systray menu */
1099 void MainInterface::showUpdateSystrayMenu()
1107 VLCMenuBar::updateSystrayMenu( this, p_intf );
1110 /* First Item of the systray menu */
1111 void MainInterface::hideUpdateSystrayMenu()
1114 VLCMenuBar::updateSystrayMenu( this, p_intf );
1117 /* Click on systray Icon */
1118 void MainInterface::handleSystrayClick(
1119 QSystemTrayIcon::ActivationReason reason )
1123 case QSystemTrayIcon::Trigger:
1124 case QSystemTrayIcon::DoubleClick:
1126 VLCMenuBar::updateSystrayMenu( this, p_intf );
1128 toggleUpdateSystrayMenu();
1131 case QSystemTrayIcon::MiddleClick:
1132 sysTray->showMessage( qtr( "VLC media player" ),
1133 qtr( "Control menu for the player" ),
1134 QSystemTrayIcon::Information, 3000 );
1142 * Updates the name of the systray Icon tooltip.
1143 * Doesn't check if the systray exists, check before you call it.
1145 void MainInterface::updateSystrayTooltipName( const QString& name )
1147 if( name.isEmpty() )
1149 sysTray->setToolTip( qtr( "VLC media player" ) );
1153 sysTray->setToolTip( name );
1154 if( ( i_notificationSetting == NOTIFICATION_ALWAYS ) ||
1155 ( i_notificationSetting == NOTIFICATION_MINIMIZED && (isMinimized() || isHidden()) ) )
1157 sysTray->showMessage( qtr( "VLC media player" ), name,
1158 QSystemTrayIcon::NoIcon, 3000 );
1162 VLCMenuBar::updateSystrayMenu( this, p_intf );
1166 * Updates the status of the systray Icon tooltip.
1167 * Doesn't check if the systray exists, check before you call it.
1169 void MainInterface::updateSystrayTooltipStatus( int i_status )
1174 sysTray->setToolTip( input_name );
1177 sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1180 sysTray->setToolTip( qtr( "VLC media player" ) );
1183 VLCMenuBar::updateSystrayMenu( this, p_intf );
1186 void MainInterface::changeEvent(QEvent *event)
1188 if( event->type() == QEvent::WindowStateChange )
1190 QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
1191 Qt::WindowStates newState = windowState();
1192 Qt::WindowStates oldState = windowStateChangeEvent->oldState();
1194 if( newState & Qt::WindowMinimized )
1196 b_hasPausedWhenMinimized = false;
1198 if( THEMIM->getIM()->playingStatus() == PLAYING_S &&
1199 THEMIM->getIM()->hasVideo() && !THEMIM->getIM()->hasVisualisation() &&
1202 b_hasPausedWhenMinimized = true;
1206 else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
1208 if( b_hasPausedWhenMinimized )
1215 QWidget::changeEvent(event);
1218 /************************************************************************
1220 ************************************************************************/
1221 void MainInterface::dropEvent(QDropEvent *event)
1223 dropEventPlay( event, true );
1229 * Event called if something is dropped onto a VLC window
1230 * \param event the event in question
1231 * \param b_play whether to play the file immediately
1232 * \param b_playlist true to add to playlist, false to add to media library
1235 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play, bool b_playlist )
1237 if( event->possibleActions() & ( Qt::CopyAction | Qt::MoveAction ) )
1238 event->setDropAction( Qt::CopyAction );
1242 const QMimeData *mimeData = event->mimeData();
1244 /* D&D of a subtitles file, add it on the fly */
1245 if( mimeData->urls().count() == 1 && THEMIM->getIM()->hasInput() )
1247 if( !input_AddSubtitle( THEMIM->getInput(),
1248 qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1256 bool first = b_play;
1257 foreach( const QUrl &url, mimeData->urls() )
1261 QString mrl = toURI( url.toEncoded().constData() );
1262 playlist_Add( THEPL, qtu(mrl), NULL,
1263 PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1264 PLAYLIST_END, b_playlist, pl_Unlocked );
1266 RecentsMRL::getInstance( p_intf )->addRecent( mrl );
1270 /* Browsers give content as text if you dnd the addressbar,
1271 so check if mimedata has valid url in text and use it
1272 if we didn't get any normal Urls()*/
1273 if( !mimeData->hasUrls() && mimeData->hasText() &&
1274 QUrl(mimeData->text()).isValid() )
1276 QString mrl = toURI( mimeData->text() );
1277 playlist_Add( THEPL, qtu(mrl), NULL,
1278 PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1279 PLAYLIST_END, b_playlist, pl_Unlocked );
1283 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1285 event->acceptProposedAction();
1287 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1289 event->acceptProposedAction();
1291 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1296 /************************************************************************
1298 ************************************************************************/
1299 void MainInterface::keyPressEvent( QKeyEvent *e )
1301 handleKeyPress( e );
1304 void MainInterface::handleKeyPress( QKeyEvent *e )
1306 if( ( ( e->modifiers() & Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) ) ||
1307 ( b_minimalView && !b_videoFullScreen && e->key() == Qt::Key_Escape ) )
1309 toggleMinimalView( !b_minimalView );
1313 int i_vlck = qtEventToVLCKey( e );
1316 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1323 void MainInterface::wheelEvent( QWheelEvent *e )
1325 int i_vlckey = qtWheelEventToVLCKey( e );
1326 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1330 void MainInterface::closeEvent( QCloseEvent *e )
1333 emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
1334 /* Accept session quit. Otherwise we break the desktop mamager. */
1338 void MainInterface::setInterfaceFullScreen( bool fs )
1341 setWindowState( windowState() | Qt::WindowFullScreen );
1343 setWindowState( windowState() & ~Qt::WindowFullScreen );
1345 void MainInterface::toggleInterfaceFullScreen()
1347 b_interfaceFullScreen = !b_interfaceFullScreen;
1348 if( !b_videoFullScreen )
1349 setInterfaceFullScreen( b_interfaceFullScreen );
1350 emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1353 void MainInterface::emitBoss()
1357 void MainInterface::setBoss()
1370 void MainInterface::emitRaise()
1374 void MainInterface::setRaise()
1380 /*****************************************************************************
1381 * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1382 * We don't show the menu directly here because we don't want the
1383 * caller to block for a too long time.
1384 *****************************************************************************/
1385 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1386 vlc_value_t old_val, vlc_value_t new_val, void *param )
1388 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1390 intf_thread_t *p_intf = (intf_thread_t *)param;
1392 if( p_intf->pf_show_dialog )
1394 p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1395 new_val.b_bool, NULL );
1401 /*****************************************************************************
1402 * IntfShowCB: callback triggered by the intf-toggle-fscontrol libvlc variable.
1403 *****************************************************************************/
1404 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1405 vlc_value_t old_val, vlc_value_t new_val, void *param )
1407 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1408 VLC_UNUSED( new_val );
1410 intf_thread_t *p_intf = (intf_thread_t *)param;
1411 p_intf->p_sys->p_mi->toggleFSC();
1417 /*****************************************************************************
1418 * IntfRaiseMainCB: callback triggered by the intf-show-main libvlc variable.
1419 *****************************************************************************/
1420 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
1421 vlc_value_t old_val, vlc_value_t new_val, void *param )
1423 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1424 VLC_UNUSED( new_val );
1426 intf_thread_t *p_intf = (intf_thread_t *)param;
1427 p_intf->p_sys->p_mi->emitRaise();
1432 /*****************************************************************************
1433 * IntfBossCB: callback triggered by the intf-boss libvlc variable.
1434 *****************************************************************************/
1435 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
1436 vlc_value_t old_val, vlc_value_t new_val, void *param )
1438 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1439 VLC_UNUSED( new_val );
1441 intf_thread_t *p_intf = (intf_thread_t *)param;
1442 p_intf->p_sys->p_mi->emitBoss();