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 if ( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY
385 && var_InheritBool( p_intf, "qt-icon-change" ) )
387 bgWidget = new EasterEggBackgroundWidget( p_intf );
388 CONNECT( this, kc_pressed(), bgWidget, animate() );
391 bgWidget = new BackgroundWidget( p_intf );
393 stackCentralW->addWidget( bgWidget );
394 if ( !var_InheritBool( p_intf, "qt-bgcone" ) )
395 bgWidget->setWithArt( false );
397 if ( var_InheritBool( p_intf, "qt-bgcone-expands" ) )
398 bgWidget->setExpandstoHeight( true );
400 /* And video Outputs */
401 if( b_videoEmbedded )
403 videoWidget = new VideoWidget( p_intf );
404 stackCentralW->addWidget( videoWidget );
406 mainLayout->insertWidget( 1, stackCentralW );
408 stackWidgetsSizes[bgWidget] =
409 creationSettings->value( "MainWindow/bgSize", QSize( 600, 0 ) ).toSize();
410 /* Resize even if no-auto-resize, because we are at creation */
411 resizeStack( stackWidgetsSizes[bgWidget].width(), stackWidgetsSizes[bgWidget].height() );
413 /* Create the CONTROLS Widget */
414 controls = new ControlsWidget( p_intf,
415 creationSettings->value( "MainWindow/adv-controls", false ).toBool(), this );
416 inputC = new InputControlsWidget( p_intf, this );
418 mainLayout->insertWidget( 2, inputC );
419 mainLayout->insertWidget(
420 creationSettings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
423 /* Visualisation, disabled for now, they SUCK */
425 visualSelector = new VisualSelector( p_intf );
426 mainLayout->insertWidget( 0, visualSelector );
427 visualSelector->hide();
431 /* Enable the popup menu in the MI */
432 main->setContextMenuPolicy( Qt::CustomContextMenu );
433 CONNECT( main, customContextMenuRequested( const QPoint& ),
434 this, popupMenu( const QPoint& ) );
436 if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
437 /* Create the FULLSCREEN CONTROLS Widget */
438 if( var_InheritBool( p_intf, "qt-fs-controller" ) )
440 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
441 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
442 this, handleKeyPress( QKeyEvent * ) );
446 inline void MainInterface::initSystray()
448 bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
449 bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
451 if( var_InheritBool( p_intf, "qt-start-minimized") )
453 if( b_systrayAvailable )
455 b_systrayWanted = true;
456 b_hideAfterCreation = true;
459 msg_Err( p_intf, "cannot start minimized without system tray bar" );
462 if( b_systrayAvailable && b_systrayWanted )
466 inline void MainInterface::createStatusBar()
471 /* Widgets Creation*/
472 QStatusBar *statusBarr = statusBar();
474 TimeLabel *timeLabel = new TimeLabel( p_intf );
475 nameLabel = new ClickableQLabel();
476 nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
477 | Qt::TextSelectableByKeyboard );
478 SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
480 /* Styling those labels */
481 timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
482 speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
483 nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
484 timeLabel->setStyleSheet(
485 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
486 speedLabel->setStyleSheet(
487 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
488 /* pad both label and its tooltip */
489 nameLabel->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
491 /* and adding those */
492 statusBarr->addWidget( nameLabel, 8 );
493 statusBarr->addPermanentWidget( speedLabel, 0 );
494 statusBarr->addPermanentWidget( timeLabel, 0 );
496 CONNECT( nameLabel, doubleClicked(), THEDP, epgDialog() );
497 /* timeLabel behaviour:
498 - double clicking opens the goto time dialog
499 - right-clicking and clicking just toggle between remaining and
501 CONNECT( timeLabel, doubleClicked(), THEDP, gotoTimeDialog() );
503 CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
504 this, showCryptedLabel( bool ) );
506 CONNECT( THEMIM->getIM(), seekRequested( float ),
507 timeLabel, setDisplayPosition( float ) );
509 /* This shouldn't be necessary, but for somehow reason, the statusBarr
510 starts at height of 20px and when a text is shown it needs more space.
511 But, as the QMainWindow policy doesn't allow statusBar to change QMW's
512 geometry, we need to force a height. If you have a better idea, please
515 statusBarr->setFixedHeight( statusBarr->sizeHint().height() + 2 );
518 /**********************************************************************
519 * Handling of sizing of the components
520 **********************************************************************/
522 void MainInterface::debug()
525 msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
526 msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
527 msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
529 msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
530 msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
531 msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
535 inline void MainInterface::showVideo() { showTab( videoWidget ); }
536 inline void MainInterface::restoreStackOldWidget()
537 { showTab( stackCentralOldWidget ); }
539 inline void MainInterface::showTab( QWidget *widget )
541 if ( !widget ) widget = bgWidget; /* trying to restore a null oldwidget */
543 if ( stackCentralOldWidget )
544 msg_Dbg( p_intf, "Old stackCentralOldWidget %s at index %i",
545 stackCentralOldWidget->metaObject()->className(),
546 stackCentralW->indexOf( stackCentralOldWidget ) );
547 msg_Dbg( p_intf, "ShowTab request for %s", widget->metaObject()->className() );
549 /* fixing when the playlist has been undocked after being hidden.
550 restoreStackOldWidget() is called when video stops but
551 stackCentralOldWidget would still be pointing to playlist */
552 if ( widget == playlistWidget && !isPlDocked() )
555 stackCentralOldWidget = stackCentralW->currentWidget();
556 stackWidgetsSizes[stackCentralOldWidget] = stackCentralW->size();
558 /* If we are playing video, embedded */
559 if( videoWidget && THEMIM->getIM()->hasVideo() )
561 /* Video -> Playlist */
562 if( videoWidget == stackCentralOldWidget && widget == playlistWidget )
564 stackCentralW->removeWidget( videoWidget );
565 videoWidget->show(); videoWidget->raise();
568 /* Playlist -> Video */
569 if( playlistWidget == stackCentralOldWidget && widget == videoWidget )
571 playlistWidget->artContainer->removeWidget( videoWidget );
572 videoWidget->show(); videoWidget->raise();
573 stackCentralW->addWidget( videoWidget );
576 /* Embedded playlist -> Non-embedded playlist */
577 if( bgWidget == stackCentralOldWidget && widget == videoWidget )
579 /* In rare case when video is started before the interface */
580 if( playlistWidget != NULL )
581 playlistWidget->artContainer->removeWidget( videoWidget );
582 videoWidget->show(); videoWidget->raise();
583 stackCentralW->addWidget( videoWidget );
584 stackCentralW->setCurrentWidget( videoWidget );
588 stackCentralW->setCurrentWidget( widget );
590 resizeStack( stackWidgetsSizes[widget].width(), stackWidgetsSizes[widget].height() );
593 msg_Dbg( p_intf, "Stack state changed to %s, index %i",
594 stackCentralW->currentWidget()->metaObject()->className(),
595 stackCentralW->currentIndex() );
596 msg_Dbg( p_intf, "New stackCentralOldWidget %s at index %i",
597 stackCentralOldWidget->metaObject()->className(),
598 stackCentralW->indexOf( stackCentralOldWidget ) );
601 /* This part is done later, to account for the new pl size */
602 if( videoWidget && THEMIM->getIM()->hasVideo() &&
603 videoWidget == stackCentralOldWidget && widget == playlistWidget )
605 playlistWidget->artContainer->addWidget( videoWidget );
606 playlistWidget->artContainer->setCurrentWidget( videoWidget );
610 void MainInterface::destroyPopupMenu()
612 VLCMenuBar::PopupMenu( p_intf, false );
615 void MainInterface::popupMenu( const QPoint & )
617 VLCMenuBar::PopupMenu( p_intf, true );
620 void MainInterface::toggleFSC()
622 if( !fullscreenControls ) return;
624 IMEvent *eShow = new IMEvent( IMEvent::FullscreenControlToggle );
625 QApplication::postEvent( fullscreenControls, eShow );
628 /****************************************************************************
630 ****************************************************************************/
634 * You must not change the state of this object or other Qt4 UI objects,
635 * from the video output thread - only from the Qt4 UI main loop thread.
636 * All window provider queries must be handled through signals or events.
637 * That's why we have all those emit statements...
639 WId MainInterface::getVideo( int *pi_x, int *pi_y,
640 unsigned int *pi_width, unsigned int *pi_height )
645 /* This is a blocking call signal. Results are returned through pointers.
646 * Beware of deadlocks! */
648 emit askGetVideo( &id, pi_x, pi_y, pi_width, pi_height );
652 void MainInterface::getVideoSlot( WId *p_id, int *pi_x, int *pi_y,
653 unsigned *pi_width, unsigned *pi_height )
655 /* Hidden or minimized, activate */
656 if( isHidden() || isMinimized() )
657 toggleUpdateSystrayMenu();
659 /* Request the videoWidget */
660 WId ret = videoWidget->request( pi_x, pi_y,
661 pi_width, pi_height, !b_autoresize );
663 if( ret ) /* The videoWidget is available */
665 /* Consider the video active now */
668 /* Ask videoWidget to resize correctly, if we are in normal mode */
669 if( !isFullScreen() && !isMaximized() && b_autoresize )
670 videoWidget->SetSizing( *pi_width, *pi_height );
674 /* Asynchronous call from the WindowClose function */
675 void MainInterface::releaseVideo( void )
677 emit askReleaseVideo();
680 /* Function that is CONNECTED to the previous emit */
681 void MainInterface::releaseVideoSlot( void )
683 /* This function is called when the embedded video window is destroyed,
684 * or in the rare case that the embedded window is still here but the
685 * Qt4 interface exits. */
686 assert( videoWidget );
687 videoWidget->release();
688 setVideoOnTop( false );
689 setVideoFullScreen( false );
691 if( stackCentralW->currentWidget() == videoWidget )
692 restoreStackOldWidget();
693 else if( playlistWidget &&
694 playlistWidget->artContainer->currentWidget() == videoWidget )
696 playlistWidget->artContainer->setCurrentIndex( 0 );
697 stackCentralW->addWidget( videoWidget );
700 /* We don't want to have a blank video to popup */
701 stackCentralOldWidget = bgWidget;
704 void MainInterface::setVideoSize( unsigned int w, unsigned int h )
706 if( !isFullScreen() && !isMaximized() )
707 videoWidget->SetSizing( w, h );
710 void MainInterface::videoSizeChanged( int w, int h )
712 if( !playlistWidget || playlistWidget->artContainer->currentWidget() != videoWidget )
716 void MainInterface::setVideoFullScreen( bool fs )
718 b_videoFullScreen = fs;
721 int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
722 /* if user hasn't defined screennumber, or screennumber that is bigger
723 * than current number of screens, take screennumber where current interface
726 if( numscreen == -1 || numscreen > QApplication::desktop()->numScreens() )
727 numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
729 QRect screenres = QApplication::desktop()->screenGeometry( numscreen );
731 /* To be sure window is on proper-screen in xinerama */
732 if( !screenres.contains( pos() ) )
734 msg_Dbg( p_intf, "Moving video to correct screen");
735 move( QPoint( screenres.x(), screenres.y() ) );
739 if( playlistWidget != NULL && playlistWidget->artContainer->currentWidget() == videoWidget )
741 showTab( videoWidget );
745 setMinimalView( true );
746 setInterfaceFullScreen( true );
750 /* TODO do we want to restore screen and position ? (when
751 * qt-fullscreen-screennumber is forced) */
752 setMinimalView( b_minimalView );
753 setInterfaceFullScreen( b_interfaceFullScreen );
758 /* Slot to change the video always-on-top flag.
759 * Emit askVideoOnTop() to invoke this from other thread. */
760 void MainInterface::setVideoOnTop( bool on_top )
762 Qt::WindowFlags oldflags = windowFlags(), newflags;
765 newflags = oldflags | Qt::WindowStaysOnTopHint;
767 newflags = oldflags & ~Qt::WindowStaysOnTopHint;
768 if( newflags != oldflags && !b_videoFullScreen )
771 setWindowFlags( newflags );
772 show(); /* necessary to apply window flags */
776 /* Asynchronous call from WindowControl function */
777 int MainInterface::controlVideo( int i_query, va_list args )
781 case VOUT_WINDOW_SET_SIZE:
783 unsigned int i_width = va_arg( args, unsigned int );
784 unsigned int i_height = va_arg( args, unsigned int );
786 emit askVideoToResize( i_width, i_height );
789 case VOUT_WINDOW_SET_STATE:
791 unsigned i_arg = va_arg( args, unsigned );
792 unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
794 emit askVideoOnTop( on_top != 0 );
797 case VOUT_WINDOW_SET_FULLSCREEN:
799 bool b_fs = va_arg( args, int );
801 emit askVideoSetFullScreen( b_fs );
805 msg_Warn( p_intf, "unsupported control query" );
810 /*****************************************************************************
811 * Playlist, Visualisation and Menus handling
812 *****************************************************************************/
814 * Toggle the playlist widget or dialog
816 void MainInterface::createPlaylist()
818 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
822 playlistWidget = dialog->exportPlaylistWidget();
823 stackCentralW->addWidget( playlistWidget );
824 stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 600, 300 ) ).toSize();
826 CONNECT( dialog, visibilityChanged(bool), this, setPlaylistVisibility(bool) );
829 void MainInterface::togglePlaylist()
831 if( !playlistWidget ) createPlaylist();
833 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
836 if ( dialog->hasPlaylistWidget() )
837 playlistWidget = dialog->exportPlaylistWidget();
838 /* Playlist is not visible, show it */
839 if( stackCentralW->currentWidget() != playlistWidget )
841 if( stackCentralW->indexOf( playlistWidget ) == -1 )
842 stackCentralW->addWidget( playlistWidget );
843 showTab( playlistWidget );
847 restoreStackOldWidget();
849 playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
853 playlistVisible = !playlistVisible;
854 if ( ! dialog->hasPlaylistWidget() )
855 dialog->importPlaylistWidget( playlistWidget );
856 if ( playlistVisible )
864 const Qt::Key MainInterface::kc[10] =
866 Qt::Key_Up, Qt::Key_Up,
867 Qt::Key_Down, Qt::Key_Down,
868 Qt::Key_Left, Qt::Key_Right, Qt::Key_Left, Qt::Key_Right,
872 void MainInterface::dockPlaylist( bool p_docked )
874 if( b_plDocked == p_docked ) return;
875 /* some extra check */
876 if ( b_plDocked && !playlistWidget ) createPlaylist();
878 b_plDocked = p_docked;
879 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
881 if( !p_docked ) /* Previously docked */
883 playlistVisible = playlistWidget->isVisible();
884 stackCentralW->removeWidget( playlistWidget );
885 dialog->importPlaylistWidget( playlistWidget );
886 if ( playlistVisible ) dialog->show();
887 restoreStackOldWidget();
889 else /* Previously undocked */
891 playlistVisible = dialog->isVisible();
893 playlistWidget = dialog->exportPlaylistWidget();
894 stackCentralW->addWidget( playlistWidget );
896 /* If playlist is invisible don't show it */
897 if( playlistVisible ) showTab( playlistWidget );
902 * setMinimalView is the private function used by
903 * the SLOT toggleMinimalView and setVideoFullScreen
905 void MainInterface::setMinimalView( bool b_minimal )
907 menuBar()->setVisible( !b_minimal );
908 controls->setVisible( !b_minimal );
909 statusBar()->setVisible( !b_minimal && b_statusbarVisible );
910 inputC->setVisible( !b_minimal );
914 * This public SLOT is used for moving to minimal View Mode
916 * If b_minimal is false, then we are normalView
918 void MainInterface::toggleMinimalView( bool b_minimal )
920 if( !b_minimalView && b_autoresize ) /* Normal mode */
922 if( stackCentralW->currentWidget() == bgWidget )
924 if( stackCentralW->height() < 16 )
926 resizeStack( stackCentralW->width(), 100 );
930 b_minimalView = b_minimal;
931 if( !b_videoFullScreen )
933 setMinimalView( b_minimalView );
934 computeMinimumSize();
937 emit minimalViewToggled( b_minimalView );
940 /* toggling advanced controls buttons */
941 void MainInterface::toggleAdvancedButtons()
943 controls->toggleAdvanced();
944 // if( fullscreenControls ) fullscreenControls->toggleAdvanced();
947 /* Get the visibility status of the controls (hidden or not, advanced or not) */
948 int MainInterface::getControlsVisibilityStatus()
950 if( !controls ) return 0;
951 return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
952 + CONTROLS_ADVANCED * controls->b_advancedVisible );
955 StandardPLPanel *MainInterface::getPlaylistView()
957 if( !playlistWidget ) return NULL;
958 else return playlistWidget->mainView;
961 void MainInterface::setStatusBarVisibility( bool b_visible )
963 statusBar()->setVisible( b_visible );
964 b_statusbarVisible = b_visible;
965 if( controls ) controls->setGripVisible( !b_statusbarVisible );
969 void MainInterface::setPlaylistVisibility( bool b_visible )
972 playlistVisible = b_visible;
976 void MainInterface::visual()
978 if( !VISIBLE( visualSelector) )
980 visualSelector->show();
981 if( !THEMIM->getIM()->hasVideo() )
983 /* Show the background widget */
985 visualSelectorEnabled = true;
989 /* Stop any currently running visualization */
990 visualSelector->hide();
991 visualSelectorEnabled = false;
996 /************************************************************************
998 ************************************************************************/
999 void MainInterface::setName( const QString& name )
1001 input_name = name; /* store it for the QSystray use */
1002 /* Display it in the status bar, but also as a Tooltip in case it doesn't
1004 nameLabel->setText( name );
1005 nameLabel->setToolTip( name );
1009 * Give the decorations of the Main Window a correct Name.
1010 * If nothing is given, set it to VLC...
1012 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
1014 if( aTitle.isEmpty() )
1016 setWindowTitle( qtr( "VLC media player" ) );
1020 setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
1024 void MainInterface::showCryptedLabel( bool b_show )
1026 if( cryptedLabel == NULL )
1028 cryptedLabel = new QLabel;
1029 // The lock icon is not the right one for DRM protection/scrambled.
1030 //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
1031 cryptedLabel->setText( "DRM" );
1032 statusBar()->addWidget( cryptedLabel );
1035 cryptedLabel->setVisible( b_show );
1038 void MainInterface::showBuffering( float f_cache )
1040 QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
1041 statusBar()->showMessage( amount, 1000 );
1044 /*****************************************************************************
1045 * Systray Icon and Systray Menu
1046 *****************************************************************************/
1048 * Create a SystemTray icon and a menu that would go with it.
1049 * Connects to a click handler on the icon.
1051 void MainInterface::createSystray()
1054 if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
1055 iconVLC = QIcon( ":/logo/vlc128-xmas.png" );
1057 iconVLC = QIcon( ":/logo/vlc128.png" );
1058 sysTray = new QSystemTrayIcon( iconVLC, this );
1059 sysTray->setToolTip( qtr( "VLC media player" ));
1061 systrayMenu = new QMenu( qtr( "VLC media player" ), this );
1062 systrayMenu->setIcon( iconVLC );
1064 VLCMenuBar::updateSystrayMenu( this, p_intf, true );
1067 CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
1068 this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
1070 /* Connects on nameChanged() */
1071 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
1072 this, updateSystrayTooltipName( const QString& ) );
1073 /* Connect PLAY_STATUS on the systray */
1074 CONNECT( THEMIM->getIM(), playingStatusChanged( int ),
1075 this, updateSystrayTooltipStatus( int ) );
1079 * Updates the Systray Icon's menu and toggle the main interface
1081 void MainInterface::toggleUpdateSystrayMenu()
1083 /* If hidden, show it */
1089 else if( isMinimized() )
1097 /* Visible (possibly under other windows) */
1099 /* check if any visible window is above vlc in the z-order,
1100 * but ignore the ones always on top
1101 * and the ones which can't be activated */
1104 wi.cbSize = sizeof( WINDOWINFO );
1105 for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
1106 hwnd && ( !IsWindowVisible( hwnd ) ||
1107 ( GetWindowInfo( hwnd, &wi ) &&
1108 (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
1109 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
1110 if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
1111 (wi.dwExStyle&WS_EX_TOPMOST) )
1124 VLCMenuBar::updateSystrayMenu( this, p_intf );
1127 /* First Item of the systray menu */
1128 void MainInterface::showUpdateSystrayMenu()
1136 VLCMenuBar::updateSystrayMenu( this, p_intf );
1139 /* First Item of the systray menu */
1140 void MainInterface::hideUpdateSystrayMenu()
1143 VLCMenuBar::updateSystrayMenu( this, p_intf );
1146 /* Click on systray Icon */
1147 void MainInterface::handleSystrayClick(
1148 QSystemTrayIcon::ActivationReason reason )
1152 case QSystemTrayIcon::Trigger:
1153 case QSystemTrayIcon::DoubleClick:
1155 VLCMenuBar::updateSystrayMenu( this, p_intf );
1157 toggleUpdateSystrayMenu();
1160 case QSystemTrayIcon::MiddleClick:
1161 sysTray->showMessage( qtr( "VLC media player" ),
1162 qtr( "Control menu for the player" ),
1163 QSystemTrayIcon::Information, 3000 );
1171 * Updates the name of the systray Icon tooltip.
1172 * Doesn't check if the systray exists, check before you call it.
1174 void MainInterface::updateSystrayTooltipName( const QString& name )
1176 if( name.isEmpty() )
1178 sysTray->setToolTip( qtr( "VLC media player" ) );
1182 sysTray->setToolTip( name );
1183 if( ( i_notificationSetting == NOTIFICATION_ALWAYS ) ||
1184 ( i_notificationSetting == NOTIFICATION_MINIMIZED && (isMinimized() || isHidden()) ) )
1186 sysTray->showMessage( qtr( "VLC media player" ), name,
1187 QSystemTrayIcon::NoIcon, 3000 );
1191 VLCMenuBar::updateSystrayMenu( this, p_intf );
1195 * Updates the status of the systray Icon tooltip.
1196 * Doesn't check if the systray exists, check before you call it.
1198 void MainInterface::updateSystrayTooltipStatus( int i_status )
1203 sysTray->setToolTip( input_name );
1206 sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1209 sysTray->setToolTip( qtr( "VLC media player" ) );
1212 VLCMenuBar::updateSystrayMenu( this, p_intf );
1215 void MainInterface::changeEvent(QEvent *event)
1217 if( event->type() == QEvent::WindowStateChange )
1219 QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
1220 Qt::WindowStates newState = windowState();
1221 Qt::WindowStates oldState = windowStateChangeEvent->oldState();
1223 if( newState & Qt::WindowMinimized )
1225 b_hasPausedWhenMinimized = false;
1227 if( THEMIM->getIM()->playingStatus() == PLAYING_S &&
1228 THEMIM->getIM()->hasVideo() && !THEMIM->getIM()->hasVisualisation() &&
1231 b_hasPausedWhenMinimized = true;
1235 else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
1237 if( b_hasPausedWhenMinimized )
1244 QWidget::changeEvent(event);
1247 /************************************************************************
1249 ************************************************************************/
1250 void MainInterface::dropEvent(QDropEvent *event)
1252 dropEventPlay( event, true );
1258 * Event called if something is dropped onto a VLC window
1259 * \param event the event in question
1260 * \param b_play whether to play the file immediately
1261 * \param b_playlist true to add to playlist, false to add to media library
1264 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play, bool b_playlist )
1266 if( event->possibleActions() & ( Qt::CopyAction | Qt::MoveAction ) )
1267 event->setDropAction( Qt::CopyAction );
1271 const QMimeData *mimeData = event->mimeData();
1273 /* D&D of a subtitles file, add it on the fly */
1274 if( mimeData->urls().count() == 1 && THEMIM->getIM()->hasInput() )
1276 if( !input_AddSubtitle( THEMIM->getInput(),
1277 qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1285 bool first = b_play;
1286 foreach( const QUrl &url, mimeData->urls() )
1290 QString mrl = toURI( url.toEncoded().constData() );
1291 playlist_Add( THEPL, qtu(mrl), NULL,
1292 PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1293 PLAYLIST_END, b_playlist, pl_Unlocked );
1295 RecentsMRL::getInstance( p_intf )->addRecent( mrl );
1299 /* Browsers give content as text if you dnd the addressbar,
1300 so check if mimedata has valid url in text and use it
1301 if we didn't get any normal Urls()*/
1302 if( !mimeData->hasUrls() && mimeData->hasText() &&
1303 QUrl(mimeData->text()).isValid() )
1305 QString mrl = toURI( mimeData->text() );
1306 playlist_Add( THEPL, qtu(mrl), NULL,
1307 PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1308 PLAYLIST_END, b_playlist, pl_Unlocked );
1312 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1314 event->acceptProposedAction();
1316 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1318 event->acceptProposedAction();
1320 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1325 /************************************************************************
1327 ************************************************************************/
1328 void MainInterface::keyPressEvent( QKeyEvent *e )
1330 handleKeyPress( e );
1332 /* easter eggs sequence handling */
1333 if ( e->key() == kc[ i_kc_offset ] )
1338 if ( i_kc_offset == (sizeof( kc ) / sizeof( Qt::Key )) )
1345 void MainInterface::handleKeyPress( QKeyEvent *e )
1347 if( ( ( e->modifiers() & Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) ) ||
1348 ( b_minimalView && !b_videoFullScreen && e->key() == Qt::Key_Escape ) )
1350 toggleMinimalView( !b_minimalView );
1354 int i_vlck = qtEventToVLCKey( e );
1357 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1364 void MainInterface::wheelEvent( QWheelEvent *e )
1366 int i_vlckey = qtWheelEventToVLCKey( e );
1367 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1371 void MainInterface::closeEvent( QCloseEvent *e )
1374 emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
1375 /* Accept session quit. Otherwise we break the desktop mamager. */
1379 bool MainInterface::eventFilter( QObject *obj, QEvent *event )
1381 if ( event->type() == MainInterface::ToolbarsNeedRebuild ) {
1386 return QObject::eventFilter( obj, event );
1390 void MainInterface::toolBarConfUpdated()
1392 QApplication::postEvent( this, new QEvent( MainInterface::ToolbarsNeedRebuild ) );
1395 void MainInterface::setInterfaceFullScreen( bool fs )
1398 setWindowState( windowState() | Qt::WindowFullScreen );
1400 setWindowState( windowState() & ~Qt::WindowFullScreen );
1402 void MainInterface::toggleInterfaceFullScreen()
1404 b_interfaceFullScreen = !b_interfaceFullScreen;
1405 if( !b_videoFullScreen )
1406 setInterfaceFullScreen( b_interfaceFullScreen );
1407 emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1410 void MainInterface::emitBoss()
1414 void MainInterface::setBoss()
1427 void MainInterface::emitRaise()
1431 void MainInterface::setRaise()
1437 /*****************************************************************************
1438 * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1439 * We don't show the menu directly here because we don't want the
1440 * caller to block for a too long time.
1441 *****************************************************************************/
1442 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1443 vlc_value_t old_val, vlc_value_t new_val, void *param )
1445 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1447 intf_thread_t *p_intf = (intf_thread_t *)param;
1449 if( p_intf->pf_show_dialog )
1451 p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1452 new_val.b_bool, NULL );
1458 /*****************************************************************************
1459 * IntfShowCB: callback triggered by the intf-toggle-fscontrol libvlc variable.
1460 *****************************************************************************/
1461 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1462 vlc_value_t old_val, vlc_value_t new_val, void *param )
1464 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1465 VLC_UNUSED( new_val );
1467 intf_thread_t *p_intf = (intf_thread_t *)param;
1468 p_intf->p_sys->p_mi->toggleFSC();
1474 /*****************************************************************************
1475 * IntfRaiseMainCB: callback triggered by the intf-show-main libvlc variable.
1476 *****************************************************************************/
1477 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
1478 vlc_value_t old_val, vlc_value_t new_val, void *param )
1480 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1481 VLC_UNUSED( new_val );
1483 intf_thread_t *p_intf = (intf_thread_t *)param;
1484 p_intf->p_sys->p_mi->emitRaise();
1489 /*****************************************************************************
1490 * IntfBossCB: callback triggered by the intf-boss libvlc variable.
1491 *****************************************************************************/
1492 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
1493 vlc_value_t old_val, vlc_value_t new_val, void *param )
1495 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1496 VLC_UNUSED( new_val );
1498 intf_thread_t *p_intf = (intf_thread_t *)param;
1499 p_intf->p_sys->p_mi->emitBoss();