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>
61 #include <QStackedWidget>
63 #include <vlc_keys.h> /* Wheel event */
64 #include <vlc_vout_display.h> /* vout_thread_t and VOUT_ events */
68 /* Callback prototypes */
69 static int PopupMenuCB( 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 IntfShowCB( 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 IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
74 vlc_value_t old_val, vlc_value_t new_val, void *param );
75 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
76 vlc_value_t old_val, vlc_value_t new_val,
79 const QEvent::Type MainInterface::ToolbarsNeedRebuild =
80 (QEvent::Type)QEvent::registerEventType();
82 MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
84 /* Variables initialisation */
87 playlistWidget = NULL;
88 stackCentralOldWidget= NULL;
90 fullscreenControls = NULL;
95 b_hideAfterCreation = false; // --qt-start-minimized
96 playlistVisible = false;
98 b_interfaceFullScreen= false;
99 b_hasPausedWhenMinimized = false;
102 /* Ask for Privacy */
103 FirstRun::CheckAndRun( this, p_intf );
106 * Configuration and settings
107 * Pre-building of interface
110 setFocusPolicy( Qt::StrongFocus );
111 setAcceptDrops( true );
112 setWindowRole( "vlc-main" );
113 setWindowIcon( QApplication::windowIcon() );
114 setWindowOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
116 setAttribute( Qt::WA_MacBrushedMetal );
119 /* Is video in embedded in the UI or not */
120 b_videoEmbedded = var_InheritBool( p_intf, "embedded-video" );
122 /* Does the interface resize to video size or the opposite */
123 b_autoresize = var_InheritBool( p_intf, "qt-video-autoresize" );
125 /* Are we in the enhanced always-video mode or not ? */
126 b_minimalView = var_InheritBool( p_intf, "qt-minimal-view" );
128 /* Do we want anoying popups or not */
129 i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
132 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
134 /* Set the other interface settings */
135 settings = getSettings();
139 p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
143 b_plDocked = getSettings()->value( "MainWindow/pl-dock-status", true ).toBool();
146 /**************************
147 * UI and Widgets design
148 **************************/
149 setVLCWindowsTitle();
154 VLCMenuBar::createMenuBar( this, p_intf );
155 CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
156 this, destroyPopupMenu() );
158 createMainWidget( settings );
164 setStatusBarVisibility( getSettings()->value( "MainWindow/status-bar-visible", false ).toBool() );
166 /********************
168 ********************/
169 MainInputManager::getInstance( p_intf );
174 taskbar_wmsg = RegisterWindowMessage("TaskbarButtonCreated");
177 /*********************************
178 * Create the Systray Management *
179 *********************************/
182 /*************************************************************
183 * Connect the input manager to the GUI elements it manages *
184 * Beware initSystray did some connects on input manager too *
185 *************************************************************/
187 * Connects on nameChanged()
188 * Those connects are different because options can impeach them to trigger.
190 /* Main Interface statusbar */
191 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
192 this, setName( const QString& ) );
193 /* and title of the Main Interface*/
194 if( var_InheritBool( p_intf, "qt-name-in-title" ) )
196 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
197 this, setVLCWindowsTitle( const QString& ) );
199 /* END CONNECTS ON IM */
201 /* VideoWidget connects for asynchronous calls */
202 b_videoFullScreen = false;
203 connect( this, SIGNAL(askGetVideo(WId*,int*,int*,unsigned*,unsigned *)),
204 this, SLOT(getVideoSlot(WId*,int*,int*,unsigned*,unsigned*)),
205 Qt::BlockingQueuedConnection );
206 connect( this, SIGNAL(askReleaseVideo( void )),
207 this, SLOT(releaseVideoSlot( void )),
208 Qt::BlockingQueuedConnection );
209 CONNECT( this, askVideoOnTop(bool), this, setVideoOnTop(bool));
215 CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
216 this, setVideoSize( unsigned int, unsigned int ) );
217 CONNECT( videoWidget, sizeChanged( int, int ),
218 this, videoSizeChanged( int, int ) );
220 CONNECT( this, askVideoSetFullScreen( bool ),
221 this, setVideoFullScreen( bool ) );
224 CONNECT( THEDP, toolBarConfUpdated(), this, toolBarConfUpdated() );
225 installEventFilter( this );
227 CONNECT( this, askToQuit(), THEDP, quit() );
229 CONNECT( this, askBoss(), this, setBoss() );
230 CONNECT( this, askRaise(), this, setRaise() );
232 /** END of CONNECTS**/
238 var_AddCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
239 var_AddCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
240 var_AddCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
242 /* Register callback for the intf-popupmenu variable */
243 var_AddCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
246 /* Final Sizing, restoration and placement of the interface */
247 if( settings->value( "MainWindow/playlist-visible", false ).toBool() )
250 QVLCTools::restoreWidgetPosition( settings, this, QSize(600, 420) );
252 b_interfaceFullScreen = isFullScreen();
254 setVisible( !b_hideAfterCreation );
256 computeMinimumSize();
258 /* Switch to minimal view if needed, must be called after the show() */
260 toggleMinimalView( true );
263 MainInterface::~MainInterface()
265 /* Unsure we hide the videoWidget before destroying it */
266 if( stackCentralOldWidget == videoWidget )
274 ImageList_Destroy( himl );
280 /* Be sure to kill the actionsManager... Only used in the MI and control */
281 ActionsManager::killInstance();
284 ExtensionsManager::killInstance();
286 /* Delete the FSC controller */
287 delete fullscreenControls;
291 settings->beginGroup("MainWindow");
292 settings->setValue( "pl-dock-status", b_plDocked );
294 /* Save playlist state */
295 settings->setValue( "playlist-visible", playlistVisible );
297 settings->setValue( "adv-controls",
298 getControlsVisibilityStatus() & CONTROLS_ADVANCED );
299 settings->setValue( "status-bar-visible", b_statusbarVisible );
301 /* Save the stackCentralW sizes */
302 settings->setValue( "bgSize", stackWidgetsSizes[bgWidget] );
303 settings->setValue( "playlistSize", stackWidgetsSizes[playlistWidget] );
304 settings->endGroup();
307 QVLCTools::saveWidgetPosition(settings, this);
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();
354 setMinimalView( b_minimalView );
357 void MainInterface::reloadPrefs()
359 i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
360 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
362 p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
364 if( !var_InheritBool( p_intf, "qt-fs-controller" ) && fullscreenControls )
366 delete fullscreenControls;
367 fullscreenControls = NULL;
371 void MainInterface::createMainWidget( QSettings *creationSettings )
373 /* Create the main Widget and the mainLayout */
374 QWidget *main = new QWidget;
375 setCentralWidget( main );
376 mainLayout = new QVBoxLayout( main );
377 main->setContentsMargins( 0, 0, 0, 0 );
378 mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
381 stackCentralW = new QVLCStackedWidget( main );
384 bgWidget = new BackgroundWidget( p_intf );
385 stackCentralW->addWidget( bgWidget );
386 if ( !var_InheritBool( p_intf, "qt-bgcone" ) )
387 bgWidget->setWithArt( false );
389 if ( var_InheritBool( p_intf, "qt-bgcone-expands" ) )
390 bgWidget->setExpandstoHeight( true );
392 /* And video Outputs */
393 if( b_videoEmbedded )
395 videoWidget = new VideoWidget( p_intf );
396 stackCentralW->addWidget( videoWidget );
398 mainLayout->insertWidget( 1, stackCentralW );
400 stackWidgetsSizes[bgWidget] =
401 creationSettings->value( "MainWindow/bgSize", QSize( 600, 0 ) ).toSize();
402 /* Resize even if no-auto-resize, because we are at creation */
403 resizeStack( stackWidgetsSizes[bgWidget].width(), stackWidgetsSizes[bgWidget].height() );
405 /* Create the CONTROLS Widget */
406 controls = new ControlsWidget( p_intf,
407 creationSettings->value( "MainWindow/adv-controls", false ).toBool(), this );
408 inputC = new InputControlsWidget( p_intf, this );
410 mainLayout->insertWidget( 2, inputC );
411 mainLayout->insertWidget(
412 creationSettings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
415 /* Visualisation, disabled for now, they SUCK */
417 visualSelector = new VisualSelector( p_intf );
418 mainLayout->insertWidget( 0, visualSelector );
419 visualSelector->hide();
423 /* Enable the popup menu in the MI */
424 main->setContextMenuPolicy( Qt::CustomContextMenu );
425 CONNECT( main, customContextMenuRequested( const QPoint& ),
426 this, popupMenu( const QPoint& ) );
428 if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
429 /* Create the FULLSCREEN CONTROLS Widget */
430 if( var_InheritBool( p_intf, "qt-fs-controller" ) )
432 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
433 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
434 this, handleKeyPress( QKeyEvent * ) );
438 inline void MainInterface::initSystray()
440 bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
441 bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
443 if( var_InheritBool( p_intf, "qt-start-minimized") )
445 if( b_systrayAvailable )
447 b_systrayWanted = true;
448 b_hideAfterCreation = true;
451 msg_Err( p_intf, "cannot start minimized without system tray bar" );
454 if( b_systrayAvailable && b_systrayWanted )
458 inline void MainInterface::createStatusBar()
463 /* Widgets Creation*/
464 QStatusBar *statusBarr = statusBar();
466 TimeLabel *timeLabel = new TimeLabel( p_intf );
467 nameLabel = new ClickableQLabel();
468 nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
469 | Qt::TextSelectableByKeyboard );
470 SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
472 /* Styling those labels */
473 timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
474 speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
475 nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
476 timeLabel->setStyleSheet(
477 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
478 speedLabel->setStyleSheet(
479 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
480 /* pad both label and its tooltip */
481 nameLabel->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
483 /* and adding those */
484 statusBarr->addWidget( nameLabel, 8 );
485 statusBarr->addPermanentWidget( speedLabel, 0 );
486 statusBarr->addPermanentWidget( timeLabel, 0 );
488 CONNECT( nameLabel, doubleClicked(), THEDP, epgDialog() );
489 /* timeLabel behaviour:
490 - double clicking opens the goto time dialog
491 - right-clicking and clicking just toggle between remaining and
493 CONNECT( timeLabel, doubleClicked(), THEDP, gotoTimeDialog() );
495 CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
496 this, showCryptedLabel( bool ) );
498 CONNECT( THEMIM->getIM(), seekRequested( float ),
499 timeLabel, setDisplayPosition( float ) );
501 /* This shouldn't be necessary, but for somehow reason, the statusBarr
502 starts at height of 20px and when a text is shown it needs more space.
503 But, as the QMainWindow policy doesn't allow statusBar to change QMW's
504 geometry, we need to force a height. If you have a better idea, please
507 statusBarr->setFixedHeight( statusBarr->sizeHint().height() + 2 );
510 /**********************************************************************
511 * Handling of sizing of the components
512 **********************************************************************/
514 void MainInterface::debug()
517 msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
518 msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
519 msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
521 msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
522 msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
523 msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
527 inline void MainInterface::showVideo() { showTab( videoWidget ); }
528 inline void MainInterface::restoreStackOldWidget()
529 { showTab( stackCentralOldWidget ); }
531 inline void MainInterface::showTab( QWidget *widget )
533 if ( !widget ) widget = bgWidget; /* trying to restore a null oldwidget */
535 if ( stackCentralOldWidget )
536 msg_Dbg( p_intf, "Old stackCentralOldWidget %s at index %i",
537 stackCentralOldWidget->metaObject()->className(),
538 stackCentralW->indexOf( stackCentralOldWidget ) );
539 msg_Dbg( p_intf, "ShowTab request for %s", widget->metaObject()->className() );
541 /* fixing when the playlist has been undocked after being hidden.
542 restoreStackOldWidget() is called when video stops but
543 stackCentralOldWidget would still be pointing to playlist */
544 if ( widget == playlistWidget && !isPlDocked() )
547 stackCentralOldWidget = stackCentralW->currentWidget();
548 stackWidgetsSizes[stackCentralOldWidget] = stackCentralW->size();
550 /* If we are playing video, embedded */
551 if( videoWidget && THEMIM->getIM()->hasVideo() )
553 /* Video -> Playlist */
554 if( videoWidget == stackCentralOldWidget && widget == playlistWidget )
556 stackCentralW->removeWidget( videoWidget );
557 videoWidget->show(); videoWidget->raise();
560 /* Playlist -> Video */
561 if( playlistWidget == stackCentralOldWidget && widget == videoWidget )
563 playlistWidget->artContainer->removeWidget( videoWidget );
564 videoWidget->show(); videoWidget->raise();
565 stackCentralW->addWidget( videoWidget );
568 /* Embedded playlist -> Non-embedded playlist */
569 if( bgWidget == stackCentralOldWidget && widget == videoWidget )
571 /* In rare case when video is started before the interface */
572 if( playlistWidget != NULL )
573 playlistWidget->artContainer->removeWidget( videoWidget );
574 videoWidget->show(); videoWidget->raise();
575 stackCentralW->addWidget( videoWidget );
576 stackCentralW->setCurrentWidget( videoWidget );
580 stackCentralW->setCurrentWidget( widget );
582 resizeStack( stackWidgetsSizes[widget].width(), stackWidgetsSizes[widget].height() );
585 msg_Dbg( p_intf, "Stack state changed to %s, index %i",
586 stackCentralW->currentWidget()->metaObject()->className(),
587 stackCentralW->currentIndex() );
588 msg_Dbg( p_intf, "New stackCentralOldWidget %s at index %i",
589 stackCentralOldWidget->metaObject()->className(),
590 stackCentralW->indexOf( stackCentralOldWidget ) );
593 /* This part is done later, to account for the new pl size */
594 if( videoWidget && THEMIM->getIM()->hasVideo() &&
595 videoWidget == stackCentralOldWidget && widget == playlistWidget )
597 playlistWidget->artContainer->addWidget( videoWidget );
598 playlistWidget->artContainer->setCurrentWidget( videoWidget );
602 void MainInterface::destroyPopupMenu()
604 VLCMenuBar::PopupMenu( p_intf, false );
607 void MainInterface::popupMenu( const QPoint & )
609 VLCMenuBar::PopupMenu( p_intf, true );
612 void MainInterface::toggleFSC()
614 if( !fullscreenControls ) return;
616 IMEvent *eShow = new IMEvent( IMEvent::FullscreenControlToggle );
617 QApplication::postEvent( fullscreenControls, eShow );
620 /****************************************************************************
622 ****************************************************************************/
626 * You must not change the state of this object or other Qt4 UI objects,
627 * from the video output thread - only from the Qt4 UI main loop thread.
628 * All window provider queries must be handled through signals or events.
629 * That's why we have all those emit statements...
631 WId MainInterface::getVideo( int *pi_x, int *pi_y,
632 unsigned int *pi_width, unsigned int *pi_height )
637 /* This is a blocking call signal. Results are returned through pointers.
638 * Beware of deadlocks! */
640 emit askGetVideo( &id, pi_x, pi_y, pi_width, pi_height );
644 void MainInterface::getVideoSlot( WId *p_id, int *pi_x, int *pi_y,
645 unsigned *pi_width, unsigned *pi_height )
647 /* Hidden or minimized, activate */
648 if( isHidden() || isMinimized() )
649 toggleUpdateSystrayMenu();
651 /* Request the videoWidget */
652 WId ret = videoWidget->request( pi_x, pi_y,
653 pi_width, pi_height, !b_autoresize );
655 if( ret ) /* The videoWidget is available */
657 /* Consider the video active now */
660 /* Ask videoWidget to resize correctly, if we are in normal mode */
661 if( !isFullScreen() && !isMaximized() && b_autoresize )
662 videoWidget->SetSizing( *pi_width, *pi_height );
666 /* Asynchronous call from the WindowClose function */
667 void MainInterface::releaseVideo( void )
669 emit askReleaseVideo();
672 /* Function that is CONNECTED to the previous emit */
673 void MainInterface::releaseVideoSlot( void )
675 /* This function is called when the embedded video window is destroyed,
676 * or in the rare case that the embedded window is still here but the
677 * Qt4 interface exits. */
678 assert( videoWidget );
679 videoWidget->release();
680 setVideoOnTop( false );
681 setVideoFullScreen( false );
683 if( stackCentralW->currentWidget() == videoWidget )
684 restoreStackOldWidget();
685 else if( playlistWidget &&
686 playlistWidget->artContainer->currentWidget() == videoWidget )
688 playlistWidget->artContainer->setCurrentIndex( 0 );
689 stackCentralW->addWidget( videoWidget );
692 /* We don't want to have a blank video to popup */
693 stackCentralOldWidget = bgWidget;
696 void MainInterface::setVideoSize( unsigned int w, unsigned int h )
698 if( !isFullScreen() && !isMaximized() )
699 videoWidget->SetSizing( w, h );
702 void MainInterface::videoSizeChanged( int w, int h )
704 if( !playlistWidget || playlistWidget->artContainer->currentWidget() != videoWidget )
708 void MainInterface::setVideoFullScreen( bool fs )
710 b_videoFullScreen = fs;
713 int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
714 /* if user hasn't defined screennumber, or screennumber that is bigger
715 * than current number of screens, take screennumber where current interface
718 if( numscreen == -1 || numscreen > QApplication::desktop()->numScreens() )
719 numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
721 QRect screenres = QApplication::desktop()->screenGeometry( numscreen );
723 /* To be sure window is on proper-screen in xinerama */
724 if( !screenres.contains( pos() ) )
726 msg_Dbg( p_intf, "Moving video to correct screen");
727 move( QPoint( screenres.x(), screenres.y() ) );
731 if( playlistWidget != NULL && playlistWidget->artContainer->currentWidget() == videoWidget )
733 showTab( videoWidget );
737 setMinimalView( true );
738 setInterfaceFullScreen( true );
742 /* TODO do we want to restore screen and position ? (when
743 * qt-fullscreen-screennumber is forced) */
744 setMinimalView( b_minimalView );
745 setInterfaceFullScreen( b_interfaceFullScreen );
750 /* Slot to change the video always-on-top flag.
751 * Emit askVideoOnTop() to invoke this from other thread. */
752 void MainInterface::setVideoOnTop( bool on_top )
754 Qt::WindowFlags oldflags = windowFlags(), newflags;
757 newflags = oldflags | Qt::WindowStaysOnTopHint;
759 newflags = oldflags & ~Qt::WindowStaysOnTopHint;
760 if( newflags != oldflags && !b_videoFullScreen )
763 setWindowFlags( newflags );
764 show(); /* necessary to apply window flags */
768 /* Asynchronous call from WindowControl function */
769 int MainInterface::controlVideo( int i_query, va_list args )
773 case VOUT_WINDOW_SET_SIZE:
775 unsigned int i_width = va_arg( args, unsigned int );
776 unsigned int i_height = va_arg( args, unsigned int );
778 emit askVideoToResize( i_width, i_height );
781 case VOUT_WINDOW_SET_STATE:
783 unsigned i_arg = va_arg( args, unsigned );
784 unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
786 emit askVideoOnTop( on_top != 0 );
789 case VOUT_WINDOW_SET_FULLSCREEN:
791 bool b_fs = va_arg( args, int );
793 emit askVideoSetFullScreen( b_fs );
797 msg_Warn( p_intf, "unsupported control query" );
802 /*****************************************************************************
803 * Playlist, Visualisation and Menus handling
804 *****************************************************************************/
806 * Toggle the playlist widget or dialog
808 void MainInterface::createPlaylist()
810 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
814 playlistWidget = dialog->exportPlaylistWidget();
815 stackCentralW->addWidget( playlistWidget );
816 stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 600, 300 ) ).toSize();
818 CONNECT( dialog, visibilityChanged(bool), this, setPlaylistVisibility(bool) );
821 void MainInterface::togglePlaylist()
823 if( !playlistWidget ) createPlaylist();
825 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
828 if ( dialog->hasPlaylistWidget() )
829 playlistWidget = dialog->exportPlaylistWidget();
830 /* Playlist is not visible, show it */
831 if( stackCentralW->currentWidget() != playlistWidget )
833 if( stackCentralW->indexOf( playlistWidget ) == -1 )
834 stackCentralW->addWidget( playlistWidget );
835 showTab( playlistWidget );
839 restoreStackOldWidget();
841 playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
845 playlistVisible = !playlistVisible;
846 if ( ! dialog->hasPlaylistWidget() )
847 dialog->importPlaylistWidget( playlistWidget );
848 if ( playlistVisible )
856 void MainInterface::dockPlaylist( bool p_docked )
858 if( b_plDocked == p_docked ) return;
859 /* some extra check */
860 if ( b_plDocked && !playlistWidget ) createPlaylist();
862 b_plDocked = p_docked;
863 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
865 if( !p_docked ) /* Previously docked */
867 playlistVisible = playlistWidget->isVisible();
868 stackCentralW->removeWidget( playlistWidget );
869 dialog->importPlaylistWidget( playlistWidget );
870 if ( playlistVisible ) dialog->show();
871 restoreStackOldWidget();
873 else /* Previously undocked */
875 playlistVisible = dialog->isVisible();
877 playlistWidget = dialog->exportPlaylistWidget();
878 stackCentralW->addWidget( playlistWidget );
880 /* If playlist is invisible don't show it */
881 if( playlistVisible ) showTab( playlistWidget );
886 * setMinimalView is the private function used by
887 * the SLOT toggleMinimalView and setVideoFullScreen
889 void MainInterface::setMinimalView( bool b_minimal )
891 menuBar()->setVisible( !b_minimal );
892 controls->setVisible( !b_minimal );
893 statusBar()->setVisible( !b_minimal && b_statusbarVisible );
894 inputC->setVisible( !b_minimal );
898 * This public SLOT is used for moving to minimal View Mode
900 * If b_minimal is false, then we are normalView
902 void MainInterface::toggleMinimalView( bool b_minimal )
904 if( !b_minimalView && b_autoresize ) /* Normal mode */
906 if( stackCentralW->currentWidget() == bgWidget )
908 if( stackCentralW->height() < 16 )
910 resizeStack( stackCentralW->width(), 100 );
914 b_minimalView = b_minimal;
915 if( !b_videoFullScreen )
917 setMinimalView( b_minimalView );
918 computeMinimumSize();
921 emit minimalViewToggled( b_minimalView );
924 /* toggling advanced controls buttons */
925 void MainInterface::toggleAdvancedButtons()
927 controls->toggleAdvanced();
928 // if( fullscreenControls ) fullscreenControls->toggleAdvanced();
931 /* Get the visibility status of the controls (hidden or not, advanced or not) */
932 int MainInterface::getControlsVisibilityStatus()
934 if( !controls ) return 0;
935 return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
936 + CONTROLS_ADVANCED * controls->b_advancedVisible );
939 StandardPLPanel *MainInterface::getPlaylistView()
941 if( !playlistWidget ) return NULL;
942 else return playlistWidget->mainView;
945 void MainInterface::setStatusBarVisibility( bool b_visible )
947 statusBar()->setVisible( b_visible );
948 b_statusbarVisible = b_visible;
949 if( controls ) controls->setGripVisible( !b_statusbarVisible );
953 void MainInterface::setPlaylistVisibility( bool b_visible )
956 playlistVisible = b_visible;
960 void MainInterface::visual()
962 if( !VISIBLE( visualSelector) )
964 visualSelector->show();
965 if( !THEMIM->getIM()->hasVideo() )
967 /* Show the background widget */
969 visualSelectorEnabled = true;
973 /* Stop any currently running visualization */
974 visualSelector->hide();
975 visualSelectorEnabled = false;
980 /************************************************************************
982 ************************************************************************/
983 void MainInterface::setName( const QString& name )
985 input_name = name; /* store it for the QSystray use */
986 /* Display it in the status bar, but also as a Tooltip in case it doesn't
988 nameLabel->setText( name );
989 nameLabel->setToolTip( name );
993 * Give the decorations of the Main Window a correct Name.
994 * If nothing is given, set it to VLC...
996 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
998 if( aTitle.isEmpty() )
1000 setWindowTitle( qtr( "VLC media player" ) );
1004 setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
1008 void MainInterface::showCryptedLabel( bool b_show )
1010 if( cryptedLabel == NULL )
1012 cryptedLabel = new QLabel;
1013 // The lock icon is not the right one for DRM protection/scrambled.
1014 //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
1015 cryptedLabel->setText( "DRM" );
1016 statusBar()->addWidget( cryptedLabel );
1019 cryptedLabel->setVisible( b_show );
1022 void MainInterface::showBuffering( float f_cache )
1024 QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
1025 statusBar()->showMessage( amount, 1000 );
1028 /*****************************************************************************
1029 * Systray Icon and Systray Menu
1030 *****************************************************************************/
1032 * Create a SystemTray icon and a menu that would go with it.
1033 * Connects to a click handler on the icon.
1035 void MainInterface::createSystray()
1038 if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
1039 iconVLC = QIcon( ":/logo/vlc128-xmas.png" );
1041 iconVLC = QIcon( ":/logo/vlc128.png" );
1042 sysTray = new QSystemTrayIcon( iconVLC, this );
1043 sysTray->setToolTip( qtr( "VLC media player" ));
1045 systrayMenu = new QMenu( qtr( "VLC media player" ), this );
1046 systrayMenu->setIcon( iconVLC );
1048 VLCMenuBar::updateSystrayMenu( this, p_intf, true );
1051 CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
1052 this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
1054 /* Connects on nameChanged() */
1055 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
1056 this, updateSystrayTooltipName( const QString& ) );
1057 /* Connect PLAY_STATUS on the systray */
1058 CONNECT( THEMIM->getIM(), playingStatusChanged( int ),
1059 this, updateSystrayTooltipStatus( int ) );
1063 * Updates the Systray Icon's menu and toggle the main interface
1065 void MainInterface::toggleUpdateSystrayMenu()
1067 /* If hidden, show it */
1073 else if( isMinimized() )
1081 /* Visible (possibly under other windows) */
1083 /* check if any visible window is above vlc in the z-order,
1084 * but ignore the ones always on top
1085 * and the ones which can't be activated */
1088 wi.cbSize = sizeof( WINDOWINFO );
1089 for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
1090 hwnd && ( !IsWindowVisible( hwnd ) ||
1091 ( GetWindowInfo( hwnd, &wi ) &&
1092 (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
1093 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
1094 if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
1095 (wi.dwExStyle&WS_EX_TOPMOST) )
1108 VLCMenuBar::updateSystrayMenu( this, p_intf );
1111 /* First Item of the systray menu */
1112 void MainInterface::showUpdateSystrayMenu()
1120 VLCMenuBar::updateSystrayMenu( this, p_intf );
1123 /* First Item of the systray menu */
1124 void MainInterface::hideUpdateSystrayMenu()
1127 VLCMenuBar::updateSystrayMenu( this, p_intf );
1130 /* Click on systray Icon */
1131 void MainInterface::handleSystrayClick(
1132 QSystemTrayIcon::ActivationReason reason )
1136 case QSystemTrayIcon::Trigger:
1137 case QSystemTrayIcon::DoubleClick:
1139 VLCMenuBar::updateSystrayMenu( this, p_intf );
1141 toggleUpdateSystrayMenu();
1144 case QSystemTrayIcon::MiddleClick:
1145 sysTray->showMessage( qtr( "VLC media player" ),
1146 qtr( "Control menu for the player" ),
1147 QSystemTrayIcon::Information, 3000 );
1155 * Updates the name of the systray Icon tooltip.
1156 * Doesn't check if the systray exists, check before you call it.
1158 void MainInterface::updateSystrayTooltipName( const QString& name )
1160 if( name.isEmpty() )
1162 sysTray->setToolTip( qtr( "VLC media player" ) );
1166 sysTray->setToolTip( name );
1167 if( ( i_notificationSetting == NOTIFICATION_ALWAYS ) ||
1168 ( i_notificationSetting == NOTIFICATION_MINIMIZED && (isMinimized() || isHidden()) ) )
1170 sysTray->showMessage( qtr( "VLC media player" ), name,
1171 QSystemTrayIcon::NoIcon, 3000 );
1175 VLCMenuBar::updateSystrayMenu( this, p_intf );
1179 * Updates the status of the systray Icon tooltip.
1180 * Doesn't check if the systray exists, check before you call it.
1182 void MainInterface::updateSystrayTooltipStatus( int i_status )
1187 sysTray->setToolTip( input_name );
1190 sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1193 sysTray->setToolTip( qtr( "VLC media player" ) );
1196 VLCMenuBar::updateSystrayMenu( this, p_intf );
1199 void MainInterface::changeEvent(QEvent *event)
1201 if( event->type() == QEvent::WindowStateChange )
1203 QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
1204 Qt::WindowStates newState = windowState();
1205 Qt::WindowStates oldState = windowStateChangeEvent->oldState();
1207 if( newState & Qt::WindowMinimized )
1209 b_hasPausedWhenMinimized = false;
1211 if( THEMIM->getIM()->playingStatus() == PLAYING_S &&
1212 THEMIM->getIM()->hasVideo() && !THEMIM->getIM()->hasVisualisation() &&
1215 b_hasPausedWhenMinimized = true;
1219 else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
1221 if( b_hasPausedWhenMinimized )
1228 QWidget::changeEvent(event);
1231 /************************************************************************
1233 ************************************************************************/
1234 void MainInterface::dropEvent(QDropEvent *event)
1236 dropEventPlay( event, true );
1242 * Event called if something is dropped onto a VLC window
1243 * \param event the event in question
1244 * \param b_play whether to play the file immediately
1245 * \param b_playlist true to add to playlist, false to add to media library
1248 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play, bool b_playlist )
1250 if( event->possibleActions() & ( Qt::CopyAction | Qt::MoveAction ) )
1251 event->setDropAction( Qt::CopyAction );
1255 const QMimeData *mimeData = event->mimeData();
1257 /* D&D of a subtitles file, add it on the fly */
1258 if( mimeData->urls().count() == 1 && THEMIM->getIM()->hasInput() )
1260 if( !input_AddSubtitle( THEMIM->getInput(),
1261 qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1269 bool first = b_play;
1270 foreach( const QUrl &url, mimeData->urls() )
1274 QString mrl = toURI( url.toEncoded().constData() );
1275 playlist_Add( THEPL, qtu(mrl), NULL,
1276 PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1277 PLAYLIST_END, b_playlist, pl_Unlocked );
1279 RecentsMRL::getInstance( p_intf )->addRecent( mrl );
1283 /* Browsers give content as text if you dnd the addressbar,
1284 so check if mimedata has valid url in text and use it
1285 if we didn't get any normal Urls()*/
1286 if( !mimeData->hasUrls() && mimeData->hasText() &&
1287 QUrl(mimeData->text()).isValid() )
1289 QString mrl = toURI( mimeData->text() );
1290 playlist_Add( THEPL, qtu(mrl), NULL,
1291 PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1292 PLAYLIST_END, b_playlist, pl_Unlocked );
1296 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1298 event->acceptProposedAction();
1300 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1302 event->acceptProposedAction();
1304 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1309 /************************************************************************
1311 ************************************************************************/
1312 void MainInterface::keyPressEvent( QKeyEvent *e )
1314 handleKeyPress( e );
1317 void MainInterface::handleKeyPress( QKeyEvent *e )
1319 if( ( ( e->modifiers() & Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) ) ||
1320 ( b_minimalView && !b_videoFullScreen && e->key() == Qt::Key_Escape ) )
1322 toggleMinimalView( !b_minimalView );
1326 int i_vlck = qtEventToVLCKey( e );
1329 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1336 void MainInterface::wheelEvent( QWheelEvent *e )
1338 int i_vlckey = qtWheelEventToVLCKey( e );
1339 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1343 void MainInterface::closeEvent( QCloseEvent *e )
1346 emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
1347 /* Accept session quit. Otherwise we break the desktop mamager. */
1351 bool MainInterface::eventFilter( QObject *obj, QEvent *event )
1353 if ( event->type() == MainInterface::ToolbarsNeedRebuild ) {
1358 return QObject::eventFilter( obj, event );
1362 void MainInterface::toolBarConfUpdated()
1364 QApplication::postEvent( this, new QEvent( MainInterface::ToolbarsNeedRebuild ) );
1367 void MainInterface::setInterfaceFullScreen( bool fs )
1370 setWindowState( windowState() | Qt::WindowFullScreen );
1372 setWindowState( windowState() & ~Qt::WindowFullScreen );
1374 void MainInterface::toggleInterfaceFullScreen()
1376 b_interfaceFullScreen = !b_interfaceFullScreen;
1377 if( !b_videoFullScreen )
1378 setInterfaceFullScreen( b_interfaceFullScreen );
1379 emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1382 void MainInterface::emitBoss()
1386 void MainInterface::setBoss()
1399 void MainInterface::emitRaise()
1403 void MainInterface::setRaise()
1409 /*****************************************************************************
1410 * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1411 * We don't show the menu directly here because we don't want the
1412 * caller to block for a too long time.
1413 *****************************************************************************/
1414 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1415 vlc_value_t old_val, vlc_value_t new_val, void *param )
1417 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1419 intf_thread_t *p_intf = (intf_thread_t *)param;
1421 if( p_intf->pf_show_dialog )
1423 p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1424 new_val.b_bool, NULL );
1430 /*****************************************************************************
1431 * IntfShowCB: callback triggered by the intf-toggle-fscontrol libvlc variable.
1432 *****************************************************************************/
1433 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1434 vlc_value_t old_val, vlc_value_t new_val, void *param )
1436 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1437 VLC_UNUSED( new_val );
1439 intf_thread_t *p_intf = (intf_thread_t *)param;
1440 p_intf->p_sys->p_mi->toggleFSC();
1446 /*****************************************************************************
1447 * IntfRaiseMainCB: callback triggered by the intf-show-main libvlc variable.
1448 *****************************************************************************/
1449 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
1450 vlc_value_t old_val, vlc_value_t new_val, void *param )
1452 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1453 VLC_UNUSED( new_val );
1455 intf_thread_t *p_intf = (intf_thread_t *)param;
1456 p_intf->p_sys->p_mi->emitRaise();
1461 /*****************************************************************************
1462 * IntfBossCB: callback triggered by the intf-boss libvlc variable.
1463 *****************************************************************************/
1464 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
1465 vlc_value_t old_val, vlc_value_t new_val, void *param )
1467 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1468 VLC_UNUSED( new_val );
1470 intf_thread_t *p_intf = (intf_thread_t *)param;
1471 p_intf->p_sys->p_mi->emitBoss();