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>
64 #include <vlc_keys.h> /* Wheel event */
65 #include <vlc_vout_display.h> /* vout_thread_t and VOUT_ events */
69 /* Callback prototypes */
70 static int PopupMenuCB( 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 IntfShowCB( 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 IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
75 vlc_value_t old_val, vlc_value_t new_val, void *param );
76 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
77 vlc_value_t old_val, vlc_value_t new_val,
80 const QEvent::Type MainInterface::ToolbarsNeedRebuild =
81 (QEvent::Type)QEvent::registerEventType();
83 MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
85 /* Variables initialisation */
88 playlistWidget = NULL;
89 stackCentralOldWidget= NULL;
91 fullscreenControls = NULL;
96 b_hideAfterCreation = false; // --qt-start-minimized
97 playlistVisible = false;
99 b_interfaceFullScreen= false;
100 b_hasPausedWhenMinimized = false;
103 /* Ask for Privacy */
104 FirstRun::CheckAndRun( this, p_intf );
107 * Configuration and settings
108 * Pre-building of interface
111 setFocusPolicy( Qt::StrongFocus );
112 setAcceptDrops( true );
113 setWindowRole( "vlc-main" );
114 setWindowIcon( QApplication::windowIcon() );
115 setWindowOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
117 setAttribute( Qt::WA_MacBrushedMetal );
120 /* Is video in embedded in the UI or not */
121 b_videoEmbedded = var_InheritBool( p_intf, "embedded-video" );
123 /* Does the interface resize to video size or the opposite */
124 b_autoresize = var_InheritBool( p_intf, "qt-video-autoresize" );
126 /* Are we in the enhanced always-video mode or not ? */
127 b_minimalView = var_InheritBool( p_intf, "qt-minimal-view" );
129 /* Do we want anoying popups or not */
130 i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
133 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
135 /* Set the other interface settings */
136 settings = getSettings();
140 p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
144 b_plDocked = getSettings()->value( "MainWindow/pl-dock-status", true ).toBool();
147 /**************************
148 * UI and Widgets design
149 **************************/
150 setVLCWindowsTitle();
155 VLCMenuBar::createMenuBar( this, p_intf );
156 CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
157 this, destroyPopupMenu() );
159 createMainWidget( settings );
165 setStatusBarVisibility( getSettings()->value( "MainWindow/status-bar-visible", false ).toBool() );
167 /********************
169 ********************/
170 MainInputManager::getInstance( p_intf );
175 taskbar_wmsg = RegisterWindowMessage(TEXT("TaskbarButtonCreated"));
178 /*********************************
179 * Create the Systray Management *
180 *********************************/
183 /*************************************************************
184 * Connect the input manager to the GUI elements it manages *
185 * Beware initSystray did some connects on input manager too *
186 *************************************************************/
188 * Connects on nameChanged()
189 * Those connects are different because options can impeach them to trigger.
191 /* Main Interface statusbar */
192 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
193 this, setName( const QString& ) );
194 /* and title of the Main Interface*/
195 if( var_InheritBool( p_intf, "qt-name-in-title" ) )
197 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
198 this, setVLCWindowsTitle( const QString& ) );
200 /* END CONNECTS ON IM */
202 /* VideoWidget connects for asynchronous calls */
203 b_videoFullScreen = false;
204 connect( this, SIGNAL(askGetVideo(WId*,int*,int*,unsigned*,unsigned *)),
205 this, SLOT(getVideoSlot(WId*,int*,int*,unsigned*,unsigned*)),
206 Qt::BlockingQueuedConnection );
207 connect( this, SIGNAL(askReleaseVideo( void )),
208 this, SLOT(releaseVideoSlot( void )),
209 Qt::BlockingQueuedConnection );
210 CONNECT( this, askVideoOnTop(bool), this, setVideoOnTop(bool));
216 CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
217 this, setVideoSize( unsigned int, unsigned int ) );
218 CONNECT( videoWidget, sizeChanged( int, int ),
219 this, videoSizeChanged( int, int ) );
221 CONNECT( this, askVideoSetFullScreen( bool ),
222 this, setVideoFullScreen( bool ) );
225 CONNECT( THEDP, toolBarConfUpdated(), this, toolBarConfUpdated() );
226 installEventFilter( this );
228 CONNECT( this, askToQuit(), THEDP, quit() );
230 CONNECT( this, askBoss(), this, setBoss() );
231 CONNECT( this, askRaise(), this, setRaise() );
233 /** END of CONNECTS**/
239 var_AddCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
240 var_AddCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
241 var_AddCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
243 /* Register callback for the intf-popupmenu variable */
244 var_AddCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
247 /* Final Sizing, restoration and placement of the interface */
248 if( settings->value( "MainWindow/playlist-visible", false ).toBool() )
251 QVLCTools::restoreWidgetPosition( settings, this, QSize(600, 420) );
253 b_interfaceFullScreen = isFullScreen();
255 setVisible( !b_hideAfterCreation );
257 computeMinimumSize();
259 /* Switch to minimal view if needed, must be called after the show() */
261 toggleMinimalView( true );
264 MainInterface::~MainInterface()
266 /* Unsure we hide the videoWidget before destroying it */
267 if( stackCentralOldWidget == videoWidget )
275 ImageList_Destroy( himl );
281 /* Be sure to kill the actionsManager... Only used in the MI and control */
282 ActionsManager::killInstance();
285 ExtensionsManager::killInstance();
287 /* Delete the FSC controller */
288 delete fullscreenControls;
292 settings->beginGroup("MainWindow");
293 settings->setValue( "pl-dock-status", b_plDocked );
295 /* Save playlist state */
296 settings->setValue( "playlist-visible", playlistVisible );
298 settings->setValue( "adv-controls",
299 getControlsVisibilityStatus() & CONTROLS_ADVANCED );
300 settings->setValue( "status-bar-visible", b_statusbarVisible );
302 /* Save the stackCentralW sizes */
303 settings->setValue( "bgSize", stackWidgetsSizes[bgWidget] );
304 settings->setValue( "playlistSize", stackWidgetsSizes[playlistWidget] );
305 settings->endGroup();
308 QVLCTools::saveWidgetPosition(settings, this);
312 /* Unregister callbacks */
313 var_DelCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
314 var_DelCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
315 var_DelCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
316 var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
318 p_intf->p_sys->p_mi = NULL;
321 void MainInterface::computeMinimumSize()
324 if( menuBar()->isVisible() )
325 minWidth += __MAX( controls->sizeHint().width(), menuBar()->sizeHint().width() );
327 setMinimumWidth( minWidth );
330 /*****************************
332 *****************************/
333 void MainInterface::recreateToolbars()
335 bool b_adv = getControlsVisibilityStatus() & CONTROLS_ADVANCED;
340 controls = new ControlsWidget( p_intf, b_adv, this );
341 inputC = new InputControlsWidget( p_intf, this );
342 mainLayout->insertWidget( 2, inputC );
343 mainLayout->insertWidget( settings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
346 if( fullscreenControls )
348 delete fullscreenControls;
349 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
350 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
351 this, handleKeyPress( QKeyEvent * ) );
352 THEMIM->requestVoutUpdate();
355 setMinimalView( b_minimalView );
358 void MainInterface::reloadPrefs()
360 i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
361 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
363 p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
365 if( !var_InheritBool( p_intf, "qt-fs-controller" ) && fullscreenControls )
367 delete fullscreenControls;
368 fullscreenControls = NULL;
372 void MainInterface::createMainWidget( QSettings *creationSettings )
374 /* Create the main Widget and the mainLayout */
375 QWidget *main = new QWidget;
376 setCentralWidget( main );
377 mainLayout = new QVBoxLayout( main );
378 main->setContentsMargins( 0, 0, 0, 0 );
379 mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
382 stackCentralW = new QVLCStackedWidget( main );
385 if ( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY
386 && var_InheritBool( p_intf, "qt-icon-change" ) )
388 bgWidget = new EasterEggBackgroundWidget( p_intf );
389 CONNECT( this, kc_pressed(), bgWidget, animate() );
392 bgWidget = new BackgroundWidget( p_intf );
394 stackCentralW->addWidget( bgWidget );
395 if ( !var_InheritBool( p_intf, "qt-bgcone" ) )
396 bgWidget->setWithArt( false );
398 if ( var_InheritBool( p_intf, "qt-bgcone-expands" ) )
399 bgWidget->setExpandstoHeight( true );
401 /* And video Outputs */
402 if( b_videoEmbedded )
404 videoWidget = new VideoWidget( p_intf );
405 stackCentralW->addWidget( videoWidget );
407 mainLayout->insertWidget( 1, stackCentralW );
409 stackWidgetsSizes[bgWidget] =
410 creationSettings->value( "MainWindow/bgSize", QSize( 600, 0 ) ).toSize();
411 /* Resize even if no-auto-resize, because we are at creation */
412 resizeStack( stackWidgetsSizes[bgWidget].width(), stackWidgetsSizes[bgWidget].height() );
414 /* Create the CONTROLS Widget */
415 controls = new ControlsWidget( p_intf,
416 creationSettings->value( "MainWindow/adv-controls", false ).toBool(), this );
417 inputC = new InputControlsWidget( p_intf, this );
419 mainLayout->insertWidget( 2, inputC );
420 mainLayout->insertWidget(
421 creationSettings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
424 /* Visualisation, disabled for now, they SUCK */
426 visualSelector = new VisualSelector( p_intf );
427 mainLayout->insertWidget( 0, visualSelector );
428 visualSelector->hide();
432 /* Enable the popup menu in the MI */
433 main->setContextMenuPolicy( Qt::CustomContextMenu );
434 CONNECT( main, customContextMenuRequested( const QPoint& ),
435 this, popupMenu( const QPoint& ) );
437 if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
438 /* Create the FULLSCREEN CONTROLS Widget */
439 if( var_InheritBool( p_intf, "qt-fs-controller" ) )
441 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
442 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
443 this, handleKeyPress( QKeyEvent * ) );
447 inline void MainInterface::initSystray()
449 bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
450 bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
452 if( var_InheritBool( p_intf, "qt-start-minimized") )
454 if( b_systrayAvailable )
456 b_systrayWanted = true;
457 b_hideAfterCreation = true;
460 msg_Err( p_intf, "cannot start minimized without system tray bar" );
463 if( b_systrayAvailable && b_systrayWanted )
467 inline void MainInterface::createStatusBar()
472 /* Widgets Creation*/
473 QStatusBar *statusBarr = statusBar();
475 TimeLabel *timeLabel = new TimeLabel( p_intf );
476 nameLabel = new ClickableQLabel();
477 nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
478 | Qt::TextSelectableByKeyboard );
479 SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
481 /* Styling those labels */
482 timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
483 speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
484 nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
485 timeLabel->setStyleSheet(
486 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
487 speedLabel->setStyleSheet(
488 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
489 /* pad both label and its tooltip */
490 nameLabel->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
492 /* and adding those */
493 statusBarr->addWidget( nameLabel, 8 );
494 statusBarr->addPermanentWidget( speedLabel, 0 );
495 statusBarr->addPermanentWidget( timeLabel, 0 );
497 CONNECT( nameLabel, doubleClicked(), THEDP, epgDialog() );
498 /* timeLabel behaviour:
499 - double clicking opens the goto time dialog
500 - right-clicking and clicking just toggle between remaining and
502 CONNECT( timeLabel, doubleClicked(), THEDP, gotoTimeDialog() );
504 CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
505 this, showCryptedLabel( bool ) );
507 CONNECT( THEMIM->getIM(), seekRequested( float ),
508 timeLabel, setDisplayPosition( float ) );
510 /* This shouldn't be necessary, but for somehow reason, the statusBarr
511 starts at height of 20px and when a text is shown it needs more space.
512 But, as the QMainWindow policy doesn't allow statusBar to change QMW's
513 geometry, we need to force a height. If you have a better idea, please
516 statusBarr->setFixedHeight( statusBarr->sizeHint().height() + 2 );
519 /**********************************************************************
520 * Handling of sizing of the components
521 **********************************************************************/
523 void MainInterface::debug()
526 msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
527 msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
528 msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
530 msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
531 msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
532 msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
536 inline void MainInterface::showVideo() { showTab( videoWidget ); }
537 inline void MainInterface::restoreStackOldWidget()
538 { showTab( stackCentralOldWidget ); }
540 inline void MainInterface::showTab( QWidget *widget )
542 if ( !widget ) widget = bgWidget; /* trying to restore a null oldwidget */
544 if ( stackCentralOldWidget )
545 msg_Dbg( p_intf, "Old stackCentralOldWidget %s at index %i",
546 stackCentralOldWidget->metaObject()->className(),
547 stackCentralW->indexOf( stackCentralOldWidget ) );
548 msg_Dbg( p_intf, "ShowTab request for %s", widget->metaObject()->className() );
550 /* fixing when the playlist has been undocked after being hidden.
551 restoreStackOldWidget() is called when video stops but
552 stackCentralOldWidget would still be pointing to playlist */
553 if ( widget == playlistWidget && !isPlDocked() )
556 stackCentralOldWidget = stackCentralW->currentWidget();
557 stackWidgetsSizes[stackCentralOldWidget] = stackCentralW->size();
559 /* If we are playing video, embedded */
560 if( videoWidget && THEMIM->getIM()->hasVideo() )
562 /* Video -> Playlist */
563 if( videoWidget == stackCentralOldWidget && widget == playlistWidget )
565 stackCentralW->removeWidget( videoWidget );
566 videoWidget->show(); videoWidget->raise();
569 /* Playlist -> Video */
570 if( playlistWidget == stackCentralOldWidget && widget == videoWidget )
572 playlistWidget->artContainer->removeWidget( videoWidget );
573 videoWidget->show(); videoWidget->raise();
574 stackCentralW->addWidget( videoWidget );
577 /* Embedded playlist -> Non-embedded playlist */
578 if( bgWidget == stackCentralOldWidget && widget == videoWidget )
580 /* In rare case when video is started before the interface */
581 if( playlistWidget != NULL )
582 playlistWidget->artContainer->removeWidget( videoWidget );
583 videoWidget->show(); videoWidget->raise();
584 stackCentralW->addWidget( videoWidget );
585 stackCentralW->setCurrentWidget( videoWidget );
589 stackCentralW->setCurrentWidget( widget );
591 resizeStack( stackWidgetsSizes[widget].width(), stackWidgetsSizes[widget].height() );
594 msg_Dbg( p_intf, "Stack state changed to %s, index %i",
595 stackCentralW->currentWidget()->metaObject()->className(),
596 stackCentralW->currentIndex() );
597 msg_Dbg( p_intf, "New stackCentralOldWidget %s at index %i",
598 stackCentralOldWidget->metaObject()->className(),
599 stackCentralW->indexOf( stackCentralOldWidget ) );
602 /* This part is done later, to account for the new pl size */
603 if( videoWidget && THEMIM->getIM()->hasVideo() &&
604 videoWidget == stackCentralOldWidget && widget == playlistWidget )
606 playlistWidget->artContainer->addWidget( videoWidget );
607 playlistWidget->artContainer->setCurrentWidget( videoWidget );
611 void MainInterface::destroyPopupMenu()
613 VLCMenuBar::PopupMenu( p_intf, false );
616 void MainInterface::popupMenu( const QPoint & )
618 VLCMenuBar::PopupMenu( p_intf, true );
621 void MainInterface::toggleFSC()
623 if( !fullscreenControls ) return;
625 IMEvent *eShow = new IMEvent( IMEvent::FullscreenControlToggle );
626 QApplication::postEvent( fullscreenControls, eShow );
629 /****************************************************************************
631 ****************************************************************************/
635 * You must not change the state of this object or other Qt4 UI objects,
636 * from the video output thread - only from the Qt4 UI main loop thread.
637 * All window provider queries must be handled through signals or events.
638 * That's why we have all those emit statements...
640 WId MainInterface::getVideo( int *pi_x, int *pi_y,
641 unsigned int *pi_width, unsigned int *pi_height )
646 /* This is a blocking call signal. Results are returned through pointers.
647 * Beware of deadlocks! */
649 emit askGetVideo( &id, pi_x, pi_y, pi_width, pi_height );
653 void MainInterface::getVideoSlot( WId *p_id, int *pi_x, int *pi_y,
654 unsigned *pi_width, unsigned *pi_height )
656 /* Hidden or minimized, activate */
657 if( isHidden() || isMinimized() )
658 toggleUpdateSystrayMenu();
660 /* Request the videoWidget */
661 WId ret = videoWidget->request( pi_x, pi_y,
662 pi_width, pi_height, !b_autoresize );
664 if( ret ) /* The videoWidget is available */
666 /* Consider the video active now */
669 /* Ask videoWidget to resize correctly, if we are in normal mode */
670 if( !isFullScreen() && !isMaximized() && b_autoresize )
671 videoWidget->SetSizing( *pi_width, *pi_height );
675 /* Asynchronous call from the WindowClose function */
676 void MainInterface::releaseVideo( void )
678 emit askReleaseVideo();
681 /* Function that is CONNECTED to the previous emit */
682 void MainInterface::releaseVideoSlot( void )
684 /* This function is called when the embedded video window is destroyed,
685 * or in the rare case that the embedded window is still here but the
686 * Qt4 interface exits. */
687 assert( videoWidget );
688 videoWidget->release();
689 setVideoOnTop( false );
690 setVideoFullScreen( false );
692 if( stackCentralW->currentWidget() == videoWidget )
693 restoreStackOldWidget();
694 else if( playlistWidget &&
695 playlistWidget->artContainer->currentWidget() == videoWidget )
697 playlistWidget->artContainer->setCurrentIndex( 0 );
698 stackCentralW->addWidget( videoWidget );
701 /* We don't want to have a blank video to popup */
702 stackCentralOldWidget = bgWidget;
705 void MainInterface::setVideoSize( unsigned int w, unsigned int h )
707 if( !isFullScreen() && !isMaximized() )
708 videoWidget->SetSizing( w, h );
711 void MainInterface::videoSizeChanged( int w, int h )
713 if( !playlistWidget || playlistWidget->artContainer->currentWidget() != videoWidget )
717 void MainInterface::setVideoFullScreen( bool fs )
719 b_videoFullScreen = fs;
722 int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
723 /* if user hasn't defined screennumber, or screennumber that is bigger
724 * than current number of screens, take screennumber where current interface
727 if( numscreen == -1 || numscreen > QApplication::desktop()->numScreens() )
728 numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
730 QRect screenres = QApplication::desktop()->screenGeometry( numscreen );
732 /* To be sure window is on proper-screen in xinerama */
733 if( !screenres.contains( pos() ) )
735 msg_Dbg( p_intf, "Moving video to correct screen");
736 move( QPoint( screenres.x(), screenres.y() ) );
740 if( playlistWidget != NULL && playlistWidget->artContainer->currentWidget() == videoWidget )
742 showTab( videoWidget );
746 setMinimalView( true );
747 setInterfaceFullScreen( true );
751 /* TODO do we want to restore screen and position ? (when
752 * qt-fullscreen-screennumber is forced) */
753 setMinimalView( b_minimalView );
754 setInterfaceFullScreen( b_interfaceFullScreen );
759 /* Slot to change the video always-on-top flag.
760 * Emit askVideoOnTop() to invoke this from other thread. */
761 void MainInterface::setVideoOnTop( bool on_top )
763 Qt::WindowFlags oldflags = windowFlags(), newflags;
766 newflags = oldflags | Qt::WindowStaysOnTopHint;
768 newflags = oldflags & ~Qt::WindowStaysOnTopHint;
769 if( newflags != oldflags && !b_videoFullScreen )
772 setWindowFlags( newflags );
773 show(); /* necessary to apply window flags */
777 /* Asynchronous call from WindowControl function */
778 int MainInterface::controlVideo( int i_query, va_list args )
782 case VOUT_WINDOW_SET_SIZE:
784 unsigned int i_width = va_arg( args, unsigned int );
785 unsigned int i_height = va_arg( args, unsigned int );
787 emit askVideoToResize( i_width, i_height );
790 case VOUT_WINDOW_SET_STATE:
792 unsigned i_arg = va_arg( args, unsigned );
793 unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
795 emit askVideoOnTop( on_top != 0 );
798 case VOUT_WINDOW_SET_FULLSCREEN:
800 bool b_fs = va_arg( args, int );
802 emit askVideoSetFullScreen( b_fs );
806 msg_Warn( p_intf, "unsupported control query" );
811 /*****************************************************************************
812 * Playlist, Visualisation and Menus handling
813 *****************************************************************************/
815 * Toggle the playlist widget or dialog
817 void MainInterface::createPlaylist()
819 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
823 playlistWidget = dialog->exportPlaylistWidget();
824 stackCentralW->addWidget( playlistWidget );
825 stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 600, 300 ) ).toSize();
827 CONNECT( dialog, visibilityChanged(bool), this, setPlaylistVisibility(bool) );
830 void MainInterface::togglePlaylist()
832 if( !playlistWidget ) createPlaylist();
834 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
837 if ( dialog->hasPlaylistWidget() )
838 playlistWidget = dialog->exportPlaylistWidget();
839 /* Playlist is not visible, show it */
840 if( stackCentralW->currentWidget() != playlistWidget )
842 if( stackCentralW->indexOf( playlistWidget ) == -1 )
843 stackCentralW->addWidget( playlistWidget );
844 showTab( playlistWidget );
848 restoreStackOldWidget();
850 playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
854 playlistVisible = !playlistVisible;
855 if ( ! dialog->hasPlaylistWidget() )
856 dialog->importPlaylistWidget( playlistWidget );
857 if ( playlistVisible )
865 const Qt::Key MainInterface::kc[10] =
867 Qt::Key_Up, Qt::Key_Up,
868 Qt::Key_Down, Qt::Key_Down,
869 Qt::Key_Left, Qt::Key_Right, Qt::Key_Left, Qt::Key_Right,
873 void MainInterface::dockPlaylist( bool p_docked )
875 if( b_plDocked == p_docked ) return;
876 /* some extra check */
877 if ( b_plDocked && !playlistWidget ) createPlaylist();
879 b_plDocked = p_docked;
880 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
882 if( !p_docked ) /* Previously docked */
884 playlistVisible = playlistWidget->isVisible();
885 stackCentralW->removeWidget( playlistWidget );
886 dialog->importPlaylistWidget( playlistWidget );
887 if ( playlistVisible ) dialog->show();
888 restoreStackOldWidget();
890 else /* Previously undocked */
892 playlistVisible = dialog->isVisible();
894 playlistWidget = dialog->exportPlaylistWidget();
895 stackCentralW->addWidget( playlistWidget );
897 /* If playlist is invisible don't show it */
898 if( playlistVisible ) showTab( playlistWidget );
903 * setMinimalView is the private function used by
904 * the SLOT toggleMinimalView and setVideoFullScreen
906 void MainInterface::setMinimalView( bool b_minimal )
908 menuBar()->setVisible( !b_minimal );
909 controls->setVisible( !b_minimal );
910 statusBar()->setVisible( !b_minimal && b_statusbarVisible );
911 inputC->setVisible( !b_minimal );
915 * This public SLOT is used for moving to minimal View Mode
917 * If b_minimal is false, then we are normalView
919 void MainInterface::toggleMinimalView( bool b_minimal )
921 if( !b_minimalView && b_autoresize ) /* Normal mode */
923 if( stackCentralW->currentWidget() == bgWidget )
925 if( stackCentralW->height() < 16 )
927 resizeStack( stackCentralW->width(), 100 );
931 b_minimalView = b_minimal;
932 if( !b_videoFullScreen )
934 setMinimalView( b_minimalView );
935 computeMinimumSize();
938 emit minimalViewToggled( b_minimalView );
941 /* toggling advanced controls buttons */
942 void MainInterface::toggleAdvancedButtons()
944 controls->toggleAdvanced();
945 // if( fullscreenControls ) fullscreenControls->toggleAdvanced();
948 /* Get the visibility status of the controls (hidden or not, advanced or not) */
949 int MainInterface::getControlsVisibilityStatus()
951 if( !controls ) return 0;
952 return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
953 + CONTROLS_ADVANCED * controls->b_advancedVisible );
956 StandardPLPanel *MainInterface::getPlaylistView()
958 if( !playlistWidget ) return NULL;
959 else return playlistWidget->mainView;
962 void MainInterface::setStatusBarVisibility( bool b_visible )
964 statusBar()->setVisible( b_visible );
965 b_statusbarVisible = b_visible;
966 if( controls ) controls->setGripVisible( !b_statusbarVisible );
970 void MainInterface::setPlaylistVisibility( bool b_visible )
973 playlistVisible = b_visible;
977 void MainInterface::visual()
979 if( !VISIBLE( visualSelector) )
981 visualSelector->show();
982 if( !THEMIM->getIM()->hasVideo() )
984 /* Show the background widget */
986 visualSelectorEnabled = true;
990 /* Stop any currently running visualization */
991 visualSelector->hide();
992 visualSelectorEnabled = false;
997 /************************************************************************
999 ************************************************************************/
1000 void MainInterface::setName( const QString& name )
1002 input_name = name; /* store it for the QSystray use */
1003 /* Display it in the status bar, but also as a Tooltip in case it doesn't
1005 nameLabel->setText( name );
1006 nameLabel->setToolTip( name );
1010 * Give the decorations of the Main Window a correct Name.
1011 * If nothing is given, set it to VLC...
1013 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
1015 if( aTitle.isEmpty() )
1017 setWindowTitle( qtr( "VLC media player" ) );
1021 setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
1025 void MainInterface::showCryptedLabel( bool b_show )
1027 if( cryptedLabel == NULL )
1029 cryptedLabel = new QLabel;
1030 // The lock icon is not the right one for DRM protection/scrambled.
1031 //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
1032 cryptedLabel->setText( "DRM" );
1033 statusBar()->addWidget( cryptedLabel );
1036 cryptedLabel->setVisible( b_show );
1039 void MainInterface::showBuffering( float f_cache )
1041 QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
1042 statusBar()->showMessage( amount, 1000 );
1045 /*****************************************************************************
1046 * Systray Icon and Systray Menu
1047 *****************************************************************************/
1049 * Create a SystemTray icon and a menu that would go with it.
1050 * Connects to a click handler on the icon.
1052 void MainInterface::createSystray()
1055 if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
1056 iconVLC = QIcon( ":/logo/vlc128-xmas.png" );
1058 iconVLC = QIcon( ":/logo/vlc128.png" );
1059 sysTray = new QSystemTrayIcon( iconVLC, this );
1060 sysTray->setToolTip( qtr( "VLC media player" ));
1062 systrayMenu = new QMenu( qtr( "VLC media player" ), this );
1063 systrayMenu->setIcon( iconVLC );
1065 VLCMenuBar::updateSystrayMenu( this, p_intf, true );
1068 CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
1069 this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
1071 /* Connects on nameChanged() */
1072 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
1073 this, updateSystrayTooltipName( const QString& ) );
1074 /* Connect PLAY_STATUS on the systray */
1075 CONNECT( THEMIM->getIM(), playingStatusChanged( int ),
1076 this, updateSystrayTooltipStatus( int ) );
1080 * Updates the Systray Icon's menu and toggle the main interface
1082 void MainInterface::toggleUpdateSystrayMenu()
1084 /* If hidden, show it */
1090 else if( isMinimized() )
1098 /* Visible (possibly under other windows) */
1100 /* check if any visible window is above vlc in the z-order,
1101 * but ignore the ones always on top
1102 * and the ones which can't be activated */
1105 wi.cbSize = sizeof( WINDOWINFO );
1106 for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
1107 hwnd && ( !IsWindowVisible( hwnd ) ||
1108 ( GetWindowInfo( hwnd, &wi ) &&
1109 (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
1110 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
1111 if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
1112 (wi.dwExStyle&WS_EX_TOPMOST) )
1125 VLCMenuBar::updateSystrayMenu( this, p_intf );
1128 /* First Item of the systray menu */
1129 void MainInterface::showUpdateSystrayMenu()
1137 VLCMenuBar::updateSystrayMenu( this, p_intf );
1140 /* First Item of the systray menu */
1141 void MainInterface::hideUpdateSystrayMenu()
1144 VLCMenuBar::updateSystrayMenu( this, p_intf );
1147 /* Click on systray Icon */
1148 void MainInterface::handleSystrayClick(
1149 QSystemTrayIcon::ActivationReason reason )
1153 case QSystemTrayIcon::Trigger:
1154 case QSystemTrayIcon::DoubleClick:
1156 VLCMenuBar::updateSystrayMenu( this, p_intf );
1158 toggleUpdateSystrayMenu();
1161 case QSystemTrayIcon::MiddleClick:
1162 sysTray->showMessage( qtr( "VLC media player" ),
1163 qtr( "Control menu for the player" ),
1164 QSystemTrayIcon::Information, 3000 );
1172 * Updates the name of the systray Icon tooltip.
1173 * Doesn't check if the systray exists, check before you call it.
1175 void MainInterface::updateSystrayTooltipName( const QString& name )
1177 if( name.isEmpty() )
1179 sysTray->setToolTip( qtr( "VLC media player" ) );
1183 sysTray->setToolTip( name );
1184 if( ( i_notificationSetting == NOTIFICATION_ALWAYS ) ||
1185 ( i_notificationSetting == NOTIFICATION_MINIMIZED && (isMinimized() || isHidden()) ) )
1187 sysTray->showMessage( qtr( "VLC media player" ), name,
1188 QSystemTrayIcon::NoIcon, 3000 );
1192 VLCMenuBar::updateSystrayMenu( this, p_intf );
1196 * Updates the status of the systray Icon tooltip.
1197 * Doesn't check if the systray exists, check before you call it.
1199 void MainInterface::updateSystrayTooltipStatus( int i_status )
1204 sysTray->setToolTip( input_name );
1207 sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1210 sysTray->setToolTip( qtr( "VLC media player" ) );
1213 VLCMenuBar::updateSystrayMenu( this, p_intf );
1216 void MainInterface::changeEvent(QEvent *event)
1218 if( event->type() == QEvent::WindowStateChange )
1220 QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
1221 Qt::WindowStates newState = windowState();
1222 Qt::WindowStates oldState = windowStateChangeEvent->oldState();
1224 if( newState & Qt::WindowMinimized )
1226 b_hasPausedWhenMinimized = false;
1228 if( THEMIM->getIM()->playingStatus() == PLAYING_S &&
1229 THEMIM->getIM()->hasVideo() && !THEMIM->getIM()->hasVisualisation() &&
1232 b_hasPausedWhenMinimized = true;
1236 else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
1238 if( b_hasPausedWhenMinimized )
1245 QWidget::changeEvent(event);
1248 /************************************************************************
1250 ************************************************************************/
1251 void MainInterface::dropEvent(QDropEvent *event)
1253 dropEventPlay( event, true );
1259 * Event called if something is dropped onto a VLC window
1260 * \param event the event in question
1261 * \param b_play whether to play the file immediately
1262 * \param b_playlist true to add to playlist, false to add to media library
1265 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play, bool b_playlist )
1267 if( event->possibleActions() & ( Qt::CopyAction | Qt::MoveAction | Qt::LinkAction ) )
1268 event->setDropAction( Qt::CopyAction );
1272 const QMimeData *mimeData = event->mimeData();
1274 /* D&D of a subtitles file, add it on the fly */
1275 if( mimeData->urls().count() == 1 && THEMIM->getIM()->hasInput() )
1277 if( !input_AddSubtitle( THEMIM->getInput(),
1278 qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1286 bool first = b_play;
1287 foreach( const QUrl &url, mimeData->urls() )
1291 QString mrl = toURI( url.toEncoded().constData() );
1292 QFileInfo info( url.toLocalFile() );
1293 if( info.exists() && info.isSymLink() )
1295 QString target = info.symLinkTarget();
1297 if( QFile::exists( target ) )
1299 url = QUrl::fromLocalFile( target );
1303 url.setUrl( target );
1305 mrl = toURI( url.toEncoded().constData() );
1307 if( mrl.length() > 0 )
1309 playlist_Add( THEPL, qtu(mrl), NULL,
1310 PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1311 PLAYLIST_END, b_playlist, pl_Unlocked );
1313 RecentsMRL::getInstance( p_intf )->addRecent( mrl );
1318 /* Browsers give content as text if you dnd the addressbar,
1319 so check if mimedata has valid url in text and use it
1320 if we didn't get any normal Urls()*/
1321 if( !mimeData->hasUrls() && mimeData->hasText() &&
1322 QUrl(mimeData->text()).isValid() )
1324 QString mrl = toURI( mimeData->text() );
1325 playlist_Add( THEPL, qtu(mrl), NULL,
1326 PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1327 PLAYLIST_END, b_playlist, pl_Unlocked );
1331 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1333 event->acceptProposedAction();
1335 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1337 event->acceptProposedAction();
1339 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1344 /************************************************************************
1346 ************************************************************************/
1347 void MainInterface::keyPressEvent( QKeyEvent *e )
1349 handleKeyPress( e );
1351 /* easter eggs sequence handling */
1352 if ( e->key() == kc[ i_kc_offset ] )
1357 if ( i_kc_offset == (sizeof( kc ) / sizeof( Qt::Key )) )
1364 void MainInterface::handleKeyPress( QKeyEvent *e )
1366 if( ( ( e->modifiers() & Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) ) ||
1367 ( b_minimalView && !b_videoFullScreen && e->key() == Qt::Key_Escape ) )
1369 toggleMinimalView( !b_minimalView );
1373 int i_vlck = qtEventToVLCKey( e );
1376 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1383 void MainInterface::wheelEvent( QWheelEvent *e )
1385 int i_vlckey = qtWheelEventToVLCKey( e );
1386 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1390 void MainInterface::closeEvent( QCloseEvent *e )
1393 emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
1394 /* Accept session quit. Otherwise we break the desktop mamager. */
1398 bool MainInterface::eventFilter( QObject *obj, QEvent *event )
1400 if ( event->type() == MainInterface::ToolbarsNeedRebuild ) {
1405 return QObject::eventFilter( obj, event );
1409 void MainInterface::toolBarConfUpdated()
1411 QApplication::postEvent( this, new QEvent( MainInterface::ToolbarsNeedRebuild ) );
1414 void MainInterface::setInterfaceFullScreen( bool fs )
1417 setWindowState( windowState() | Qt::WindowFullScreen );
1419 setWindowState( windowState() & ~Qt::WindowFullScreen );
1421 void MainInterface::toggleInterfaceFullScreen()
1423 b_interfaceFullScreen = !b_interfaceFullScreen;
1424 if( !b_videoFullScreen )
1425 setInterfaceFullScreen( b_interfaceFullScreen );
1426 emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1429 void MainInterface::emitBoss()
1433 void MainInterface::setBoss()
1446 void MainInterface::emitRaise()
1450 void MainInterface::setRaise()
1456 /*****************************************************************************
1457 * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1458 * We don't show the menu directly here because we don't want the
1459 * caller to block for a too long time.
1460 *****************************************************************************/
1461 static int PopupMenuCB( 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 );
1466 intf_thread_t *p_intf = (intf_thread_t *)param;
1468 if( p_intf->pf_show_dialog )
1470 p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1471 new_val.b_bool, NULL );
1477 /*****************************************************************************
1478 * IntfShowCB: callback triggered by the intf-toggle-fscontrol libvlc variable.
1479 *****************************************************************************/
1480 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1481 vlc_value_t old_val, vlc_value_t new_val, void *param )
1483 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1484 VLC_UNUSED( new_val );
1486 intf_thread_t *p_intf = (intf_thread_t *)param;
1487 p_intf->p_sys->p_mi->toggleFSC();
1493 /*****************************************************************************
1494 * IntfRaiseMainCB: callback triggered by the intf-show-main libvlc variable.
1495 *****************************************************************************/
1496 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
1497 vlc_value_t old_val, vlc_value_t new_val, void *param )
1499 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1500 VLC_UNUSED( new_val );
1502 intf_thread_t *p_intf = (intf_thread_t *)param;
1503 p_intf->p_sys->p_mi->emitRaise();
1508 /*****************************************************************************
1509 * IntfBossCB: callback triggered by the intf-boss libvlc variable.
1510 *****************************************************************************/
1511 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
1512 vlc_value_t old_val, vlc_value_t new_val, void *param )
1514 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1515 VLC_UNUSED( new_val );
1517 intf_thread_t *p_intf = (intf_thread_t *)param;
1518 p_intf->p_sys->p_mi->emitBoss();