gui: qt: use float for rate
[vlc.git] / modules / gui / qt / main_interface.cpp
blobb243b789f2ce6df0b37c930b2ec0a30ca14074ec
1 /*****************************************************************************
2 * main_interface.cpp : Main interface
3 ****************************************************************************
4 * Copyright (C) 2006-2011 VideoLAN and AUTHORS
6 * Authors: Clément Stenac <zorglub@videolan.org>
7 * Jean-Baptiste Kempf <jb@videolan.org>
8 * Ilkka Ollakka <ileoo@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 #include "qt.hpp"
31 #include "main_interface.hpp"
32 #include "input_manager.hpp" // Creation
33 #include "actions_manager.hpp" // killInstance
34 #include "managers/renderer_manager.hpp"
36 #include "util/customwidgets.hpp" // qtEventToVLCKey, QVLCStackedWidget
37 #include "util/qt_dirs.hpp" // toNativeSeparators
38 #include "util/imagehelper.hpp"
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>
50 #include <QKeyEvent>
52 #include <QUrl>
53 #include <QSize>
54 #include <QDate>
55 #include <QMimeData>
57 #include <QWindow>
58 #include <QMenu>
59 #include <QMenuBar>
60 #include <QStatusBar>
61 #include <QLabel>
62 #include <QStackedWidget>
63 #include <QScreen>
64 #ifdef _WIN32
65 #include <QFileInfo>
66 #endif
68 #if ! HAS_QT510 && defined(QT5_HAS_X11)
69 # include <QX11Info>
70 # include <X11/Xlib.h>
71 #endif
73 #include <QTimer>
75 #include <vlc_actions.h> /* Wheel event */
76 #include <vlc_vout_window.h> /* VOUT_ events */
78 // #define DEBUG_INTF
80 /* Callback prototypes */
81 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
82 vlc_value_t old_val, vlc_value_t new_val, void *param );
83 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
84 vlc_value_t old_val, vlc_value_t new_val, void *param );
85 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
86 vlc_value_t old_val, vlc_value_t new_val, void *param );
87 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
88 vlc_value_t old_val, vlc_value_t new_val,
89 void *param );
91 const QEvent::Type MainInterface::ToolbarsNeedRebuild =
92 (QEvent::Type)QEvent::registerEventType();
94 MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf ),
95 videoActive( ATOMIC_FLAG_INIT )
97 /* Variables initialisation */
98 bgWidget = NULL;
99 videoWidget = NULL;
100 playlistWidget = NULL;
101 stackCentralOldWidget= NULL;
102 lastWinScreen = NULL;
103 sysTray = NULL;
104 fullscreenControls = NULL;
105 cryptedLabel = NULL;
106 controls = NULL;
107 inputC = NULL;
109 b_hideAfterCreation = false; // --qt-start-minimized
110 playlistVisible = false;
111 input_name = "";
112 b_interfaceFullScreen= false;
113 b_hasPausedWhenMinimized = false;
114 i_kc_offset = false;
115 b_maximizedView = false;
116 b_isWindowTiled = false;
118 /* Ask for Privacy */
119 FirstRun::CheckAndRun( this, p_intf );
122 * Configuration and settings
123 * Pre-building of interface
125 /* Main settings */
126 setFocusPolicy( Qt::StrongFocus );
127 setAcceptDrops( true );
128 setWindowRole( "vlc-main" );
129 setWindowIcon( QApplication::windowIcon() );
130 setWindowOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
132 /* Does the interface resize to video size or the opposite */
133 b_autoresize = var_InheritBool( p_intf, "qt-video-autoresize" );
135 /* Are we in the enhanced always-video mode or not ? */
136 b_minimalView = var_InheritBool( p_intf, "qt-minimal-view" );
138 /* Do we want anoying popups or not */
139 i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
141 /* */
142 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
144 /* Set the other interface settings */
145 settings = getSettings();
147 /* */
148 b_plDocked = getSettings()->value( "MainWindow/pl-dock-status", true ).toBool();
150 /* Should the UI stays on top of other windows */
151 b_interfaceOnTop = var_InheritBool( p_intf, "video-on-top" );
153 #ifdef QT5_HAS_WAYLAND
154 b_hasWayland = QGuiApplication::platformName()
155 .startsWith(QLatin1String("wayland"), Qt::CaseInsensitive);
156 #endif
158 /**************************
159 * UI and Widgets design
160 **************************/
161 setVLCWindowsTitle();
163 /************
164 * Menu Bar *
165 ************/
166 VLCMenuBar::createMenuBar( this, p_intf );
167 CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
168 THEDP, destroyPopupMenu() );
170 createMainWidget( settings );
172 /**************
173 * Status Bar *
174 **************/
175 createStatusBar();
176 setStatusBarVisibility( getSettings()->value( "MainWindow/status-bar-visible", false ).toBool() );
178 /*********************************
179 * Create the Systray Management *
180 *********************************/
181 initSystray();
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 CONNECT( THEMIM, inputChanged( bool ), this, onInputChanged( bool ) );
202 /* END CONNECTS ON IM */
204 /* VideoWidget connects for asynchronous calls */
205 b_videoFullScreen = false;
206 connect( this, SIGNAL(askGetVideo(struct vout_window_t*, unsigned, unsigned, bool)),
207 this, SLOT(getVideoSlot(struct vout_window_t*, unsigned, unsigned, bool)),
208 Qt::BlockingQueuedConnection );
209 connect( this, SIGNAL(askReleaseVideo( void )),
210 this, SLOT(releaseVideoSlot( void )),
211 Qt::BlockingQueuedConnection );
212 CONNECT( this, askVideoOnTop(bool), this, setVideoOnTop(bool));
214 if( videoWidget )
216 if( b_autoresize )
218 CONNECT( videoWidget, sizeChanged( int, int ),
219 this, videoSizeChanged( int, int ) );
221 CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
222 this, setVideoSize( unsigned int, unsigned int ) );
224 CONNECT( this, askVideoSetFullScreen( bool ),
225 this, setVideoFullScreen( bool ) );
228 CONNECT( THEDP, toolBarConfUpdated(), this, toolBarConfUpdated() );
229 installEventFilter( this );
231 CONNECT( this, askToQuit(), THEDP, quit() );
233 CONNECT( this, askBoss(), this, setBoss() );
234 CONNECT( this, askRaise(), this, setRaise() );
237 connect( THEDP, &DialogsProvider::releaseMouseEvents, this, &MainInterface::voutReleaseMouseEvents ) ;
238 /** END of CONNECTS**/
241 /************
242 * Callbacks
243 ************/
244 var_AddCallback( pl_Get(p_intf), "intf-toggle-fscontrol", IntfShowCB, p_intf );
245 var_AddCallback( pl_Get(p_intf), "intf-boss", IntfBossCB, p_intf );
246 var_AddCallback( pl_Get(p_intf), "intf-show", IntfRaiseMainCB, p_intf );
248 /* Register callback for the intf-popupmenu variable */
249 var_AddCallback( pl_Get(p_intf), "intf-popupmenu", PopupMenuCB, p_intf );
252 /* Final Sizing, restoration and placement of the interface */
253 if( settings->value( "MainWindow/playlist-visible", false ).toBool() )
254 togglePlaylist();
256 QVLCTools::restoreWidgetPosition( settings, this, QSize(600, 420) );
258 b_interfaceFullScreen = isFullScreen();
260 setVisible( !b_hideAfterCreation );
262 /* Switch to minimal view if needed, must be called after the show() */
263 if( b_minimalView )
264 toggleMinimalView( true );
266 computeMinimumSize();
269 MainInterface::~MainInterface()
271 /* Unsure we hide the videoWidget before destroying it */
272 if( stackCentralOldWidget == videoWidget )
273 showTab( bgWidget );
275 if( videoWidget )
276 releaseVideoSlot();
278 /* Be sure to kill the actionsManager... Only used in the MI and control */
279 ActionsManager::killInstance();
281 /* Delete the FSC controller */
282 delete fullscreenControls;
284 RendererManager::killInstance();
286 /* Save states */
288 settings->beginGroup("MainWindow");
289 settings->setValue( "pl-dock-status", b_plDocked );
291 /* Save playlist state */
292 settings->setValue( "playlist-visible", playlistVisible );
294 settings->setValue( "adv-controls",
295 getControlsVisibilityStatus() & CONTROLS_ADVANCED );
296 settings->setValue( "status-bar-visible", b_statusbarVisible );
298 /* Save the stackCentralW sizes */
299 settings->setValue( "bgSize", stackWidgetsSizes[bgWidget] );
300 settings->setValue( "playlistSize", stackWidgetsSizes[playlistWidget] );
301 settings->endGroup();
303 /* Save this size */
304 QVLCTools::saveWidgetPosition(settings, this);
306 /* Unregister callbacks */
307 var_DelCallback( pl_Get(p_intf), "intf-boss", IntfBossCB, p_intf );
308 var_DelCallback( pl_Get(p_intf), "intf-show", IntfRaiseMainCB, p_intf );
309 var_DelCallback( pl_Get(p_intf), "intf-toggle-fscontrol", IntfShowCB, p_intf );
310 var_DelCallback( pl_Get(p_intf), "intf-popupmenu", PopupMenuCB, p_intf );
312 p_intf->p_sys->p_mi = NULL;
315 void MainInterface::computeMinimumSize()
317 int minWidth = 80;
318 if( menuBar()->isVisible() )
319 minWidth += controls->sizeHint().width();
321 setMinimumWidth( minWidth );
324 /*****************************
325 * Main UI handling *
326 *****************************/
327 void MainInterface::recreateToolbars()
329 bool b_adv = getControlsVisibilityStatus() & CONTROLS_ADVANCED;
331 delete controls;
332 delete inputC;
334 controls = new ControlsWidget( p_intf, b_adv, this );
335 inputC = new InputControlsWidget( p_intf, this );
336 mainLayout->insertWidget( 2, inputC );
337 mainLayout->insertWidget( settings->value( "MainWindow/ToolbarPos", false ).toBool() ? 0: 3,
338 controls );
340 if( fullscreenControls )
342 delete fullscreenControls;
343 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
344 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
345 this, handleKeyPress( QKeyEvent * ) );
346 THEMIM->requestVoutUpdate();
349 setMinimalView( b_minimalView );
352 void MainInterface::reloadPrefs()
354 i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
355 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
356 if( !var_InheritBool( p_intf, "qt-fs-controller" ) && fullscreenControls )
358 delete fullscreenControls;
359 fullscreenControls = NULL;
363 void MainInterface::createResumePanel( QWidget *w )
365 resumePanel = new QWidget( w );
366 resumePanel->hide();
367 QHBoxLayout *resumePanelLayout = new QHBoxLayout( resumePanel );
368 resumePanelLayout->setSpacing( 0 ); resumePanelLayout->setMargin( 0 );
370 QLabel *continuePixmapLabel = new QLabel();
371 continuePixmapLabel->setPixmap( ImageHelper::loadSvgToPixmap( ":/menu/help.svg" , fontMetrics().height(), fontMetrics().height()) );
372 continuePixmapLabel->setContentsMargins( 5, 0, 5, 0 );
374 QLabel *continueLabel = new QLabel( qtr( "Do you want to restart the playback where left off?") );
376 QToolButton *cancel = new QToolButton( resumePanel );
377 cancel->setAutoRaise( true );
378 cancel->setText( "X" );
380 QPushButton *ok = new QPushButton( qtr( "&Continue" ) );
382 resumePanelLayout->addWidget( continuePixmapLabel );
383 resumePanelLayout->addWidget( continueLabel );
384 resumePanelLayout->addStretch( 1 );
385 resumePanelLayout->addWidget( ok );
386 resumePanelLayout->addWidget( cancel );
388 resumeTimer = new QTimer( resumePanel );
389 resumeTimer->setSingleShot( true );
390 resumeTimer->setInterval( 6000 );
392 CONNECT( resumeTimer, timeout(), this, hideResumePanel() );
393 CONNECT( cancel, clicked(), this, hideResumePanel() );
394 CONNECT( THEMIM->getIM(), resumePlayback(vlc_tick_t), this, showResumePanel(vlc_tick_t) );
395 BUTTONACT( ok, resumePlayback() );
397 w->layout()->addWidget( resumePanel );
400 void MainInterface::showResumePanel( vlc_tick_t _time ) {
401 int setting = var_InheritInteger( p_intf, "qt-continue" );
403 if( setting == 0 )
404 return;
406 i_resumeTime = _time;
408 if( setting == 2)
409 resumePlayback();
410 else
412 if( !isFullScreen() && !isMaximized() && !b_isWindowTiled )
413 resizeWindow( width(), height() + resumePanel->height() );
414 resumePanel->setVisible(true);
415 resumeTimer->start();
419 void MainInterface::hideResumePanel()
421 if( resumePanel->isVisible() )
423 if( !isFullScreen() && !isMaximized() && !b_isWindowTiled )
424 resizeWindow( width(), height() - resumePanel->height() );
425 resumePanel->hide();
426 resumeTimer->stop();
430 void MainInterface::resumePlayback()
432 if( THEMIM->getIM()->hasInput() ) {
433 var_SetInteger( THEMIM->getInput(), "time", i_resumeTime );
435 hideResumePanel();
438 void MainInterface::onInputChanged( bool hasInput )
440 if( hasInput == false )
441 return;
442 int autoRaise = var_InheritInteger( p_intf, "qt-auto-raise" );
443 if ( autoRaise == MainInterface::RAISE_NEVER )
444 return;
445 if( THEMIM->getIM()->hasVideo() == true )
447 if( ( autoRaise & MainInterface::RAISE_VIDEO ) == 0 )
448 return;
450 else if ( ( autoRaise & MainInterface::RAISE_AUDIO ) == 0 )
451 return;
452 emit askRaise();
455 void MainInterface::createMainWidget( QSettings *creationSettings )
457 /* Create the main Widget and the mainLayout */
458 QWidget *main = new QWidget;
459 setCentralWidget( main );
460 mainLayout = new QVBoxLayout( main );
461 main->setContentsMargins( 0, 0, 0, 0 );
462 mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
464 createResumePanel( main );
465 /* */
466 stackCentralW = new QVLCStackedWidget( main );
468 /* Bg Cone */
469 if ( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY
470 && var_InheritBool( p_intf, "qt-icon-change" ) )
472 bgWidget = new EasterEggBackgroundWidget( p_intf );
473 CONNECT( this, kc_pressed(), bgWidget, animate() );
475 else
476 bgWidget = new BackgroundWidget( p_intf );
478 stackCentralW->addWidget( bgWidget );
479 if ( !var_InheritBool( p_intf, "qt-bgcone" ) )
480 bgWidget->setWithArt( false );
481 else
482 if ( var_InheritBool( p_intf, "qt-bgcone-expands" ) )
483 bgWidget->setExpandstoHeight( true );
485 /* And video Outputs */
486 if( var_InheritBool( p_intf, "embedded-video" ) )
488 videoWidget = new VideoWidget( p_intf, stackCentralW );
489 stackCentralW->addWidget( videoWidget );
491 mainLayout->insertWidget( 1, stackCentralW );
493 stackWidgetsSizes[bgWidget] =
494 creationSettings->value( "MainWindow/bgSize", QSize( 600, 0 ) ).toSize();
495 /* Resize even if no-auto-resize, because we are at creation */
496 resizeStack( stackWidgetsSizes[bgWidget].width(), stackWidgetsSizes[bgWidget].height() );
498 /* Create the CONTROLS Widget */
499 controls = new ControlsWidget( p_intf,
500 creationSettings->value( "MainWindow/adv-controls", false ).toBool(), this );
501 inputC = new InputControlsWidget( p_intf, this );
503 mainLayout->insertWidget( 2, inputC );
504 mainLayout->insertWidget(
505 creationSettings->value( "MainWindow/ToolbarPos", false ).toBool() ? 0: 3,
506 controls );
508 /* Visualisation, disabled for now, they SUCK */
509 #if 0
510 visualSelector = new VisualSelector( p_intf );
511 mainLayout->insertWidget( 0, visualSelector );
512 visualSelector->hide();
513 #endif
516 /* Enable the popup menu in the MI */
517 main->setContextMenuPolicy( Qt::CustomContextMenu );
518 CONNECT( main, customContextMenuRequested( const QPoint& ),
519 THEDP, setPopupMenu() );
521 if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
522 /* Create the FULLSCREEN CONTROLS Widget */
523 if( var_InheritBool( p_intf, "qt-fs-controller" ) )
525 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
526 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
527 this, handleKeyPress( QKeyEvent * ) );
530 if ( b_interfaceOnTop )
531 setWindowFlags( windowFlags() | Qt::WindowStaysOnTopHint );
534 inline void MainInterface::initSystray()
536 bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
537 bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
539 if( var_InheritBool( p_intf, "qt-start-minimized") )
541 if( b_systrayAvailable )
543 b_systrayWanted = true;
544 b_hideAfterCreation = true;
546 else
547 msg_Err( p_intf, "cannot start minimized without system tray bar" );
550 if( b_systrayAvailable && b_systrayWanted )
551 createSystray();
554 inline void MainInterface::createStatusBar()
556 /****************
557 * Status Bar *
558 ****************/
559 /* Widgets Creation*/
560 QStatusBar *statusBarr = statusBar();
562 TimeLabel *timeLabel = new TimeLabel( p_intf );
563 nameLabel = new ClickableQLabel();
564 nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
565 | Qt::TextSelectableByKeyboard );
566 SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
568 /* Styling those labels */
569 timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
570 speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
571 nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
572 timeLabel->setStyleSheet(
573 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
574 speedLabel->setStyleSheet(
575 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
576 /* pad both label and its tooltip */
577 nameLabel->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
579 /* and adding those */
580 statusBarr->addWidget( nameLabel, 8 );
581 statusBarr->addPermanentWidget( speedLabel, 0 );
582 statusBarr->addPermanentWidget( timeLabel, 0 );
584 CONNECT( nameLabel, doubleClicked(), THEDP, epgDialog() );
585 /* timeLabel behaviour:
586 - double clicking opens the goto time dialog
587 - right-clicking and clicking just toggle between remaining and
588 elapsed time.*/
589 CONNECT( timeLabel, doubleClicked(), THEDP, gotoTimeDialog() );
591 CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
592 this, showCryptedLabel( bool ) );
594 /* This shouldn't be necessary, but for somehow reason, the statusBarr
595 starts at height of 20px and when a text is shown it needs more space.
596 But, as the QMainWindow policy doesn't allow statusBar to change QMW's
597 geometry, we need to force a height. If you have a better idea, please
598 tell me -- jb
600 statusBarr->setFixedHeight( statusBarr->sizeHint().height() + 2 );
603 /**********************************************************************
604 * Handling of sizing of the components
605 **********************************************************************/
607 void MainInterface::debug()
609 #ifdef DEBUG_INTF
610 if( controls ) {
611 msg_Dbg( p_intf, "Controls size: %i - %i", controls->size().height(), controls->size().width() );
612 msg_Dbg( p_intf, "Controls minimumsize: %i - %i", controls->minimumSize().height(), controls->minimumSize().width() );
613 msg_Dbg( p_intf, "Controls sizeHint: %i - %i", controls->sizeHint().height(), controls->sizeHint().width() );
616 msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
617 msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
618 msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
620 msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
621 msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
622 msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
623 #endif
626 inline void MainInterface::showVideo() { showTab( videoWidget ); }
627 inline void MainInterface::restoreStackOldWidget( bool video_closing )
628 { showTab( stackCentralOldWidget, video_closing ); }
630 inline void MainInterface::showTab( QWidget *widget, bool video_closing )
632 if ( !widget ) widget = bgWidget; /* trying to restore a null oldwidget */
633 #ifdef DEBUG_INTF
634 if ( stackCentralOldWidget )
635 msg_Dbg( p_intf, "Old stackCentralOldWidget %s at index %i",
636 stackCentralOldWidget->metaObject()->className(),
637 stackCentralW->indexOf( stackCentralOldWidget ) );
638 msg_Dbg( p_intf, "ShowTab request for %s", widget->metaObject()->className() );
639 #endif
640 if ( stackCentralW->currentWidget() == widget )
641 return;
643 /* fixing when the playlist has been undocked after being hidden.
644 restoreStackOldWidget() is called when video stops but
645 stackCentralOldWidget would still be pointing to playlist */
646 if ( widget == playlistWidget && !isPlDocked() )
647 widget = bgWidget;
649 stackCentralOldWidget = stackCentralW->currentWidget();
650 if( !isFullScreen() )
651 stackWidgetsSizes[stackCentralOldWidget] = stackCentralW->size();
653 /* If we are playing video, embedded */
654 if( !video_closing && videoWidget && THEMIM->getIM()->hasVideo() )
656 /* Video -> Playlist */
657 if( videoWidget == stackCentralOldWidget && widget == playlistWidget )
659 stackCentralW->removeWidget( videoWidget );
660 videoWidget->show(); videoWidget->raise();
663 /* Playlist -> Video */
664 if( playlistWidget == stackCentralOldWidget && widget == videoWidget )
666 playlistWidget->artContainer->removeWidget( videoWidget );
667 videoWidget->show(); videoWidget->raise();
668 stackCentralW->addWidget( videoWidget );
671 /* Embedded playlist -> Non-embedded playlist */
672 if( bgWidget == stackCentralOldWidget && widget == videoWidget )
674 /* In rare case when video is started before the interface */
675 if( playlistWidget != NULL )
676 playlistWidget->artContainer->removeWidget( videoWidget );
677 videoWidget->show(); videoWidget->raise();
678 stackCentralW->addWidget( videoWidget );
679 stackCentralW->setCurrentWidget( videoWidget );
683 stackCentralW->setCurrentWidget( widget );
684 if( b_autoresize )
686 QSize size = stackWidgetsSizes[widget];
687 if( size.isValid() )
688 resizeStack( size.width(), size.height() );
691 #ifdef DEBUG_INTF
692 msg_Dbg( p_intf, "Stack state changed to %s, index %i",
693 stackCentralW->currentWidget()->metaObject()->className(),
694 stackCentralW->currentIndex() );
695 msg_Dbg( p_intf, "New stackCentralOldWidget %s at index %i",
696 stackCentralOldWidget->metaObject()->className(),
697 stackCentralW->indexOf( stackCentralOldWidget ) );
698 #endif
700 /* This part is done later, to account for the new pl size */
701 if( !video_closing && videoWidget && THEMIM->getIM()->hasVideo() &&
702 videoWidget == stackCentralOldWidget && widget == playlistWidget )
704 playlistWidget->artContainer->addWidget( videoWidget );
705 playlistWidget->artContainer->setCurrentWidget( videoWidget );
709 void MainInterface::toggleFSC()
711 if( !fullscreenControls ) return;
713 IMEvent *eShow = new IMEvent( IMEvent::FullscreenControlToggle );
714 QApplication::postEvent( fullscreenControls, eShow );
717 /****************************************************************************
718 * Video Handling
719 ****************************************************************************/
722 * NOTE:
723 * You must not change the state of this object or other Qt UI objects,
724 * from the video output thread - only from the Qt UI main loop thread.
725 * All window provider queries must be handled through signals or events.
726 * That's why we have all those emit statements...
728 bool MainInterface::getVideo( struct vout_window_t *p_wnd )
730 static const struct vout_window_operations ops = {
731 MainInterface::enableVideo,
732 MainInterface::disableVideo,
733 MainInterface::resizeVideo,
734 MainInterface::releaseVideo,
735 MainInterface::requestVideoState,
736 MainInterface::requestVideoWindowed,
737 MainInterface::requestVideoFullScreen,
740 if( videoActive.test_and_set() )
741 return false;
743 p_wnd->ops = &ops;
744 p_wnd->info.has_double_click = true;
745 p_wnd->sys = this;
746 return true;
749 void MainInterface::getVideoSlot( struct vout_window_t *p_wnd,
750 unsigned i_width, unsigned i_height,
751 bool fullscreen )
753 /* Hidden or minimized, activate */
754 if( isHidden() || isMinimized() )
755 toggleUpdateSystrayMenu();
757 /* Request the videoWidget */
758 if ( !videoWidget )
760 videoWidget = new VideoWidget( p_intf, stackCentralW );
761 stackCentralW->addWidget( videoWidget );
764 videoWidget->request( p_wnd );
765 if( true ) /* The videoWidget is available */
767 setVideoFullScreen( fullscreen );
769 /* Consider the video active now */
770 showVideo();
772 /* Ask videoWidget to resize correctly, if we are in normal mode */
773 if( b_autoresize ) {
774 #if HAS_QT56
775 qreal factor = videoWidget->devicePixelRatioF();
777 i_width = qRound( (qreal) i_width / factor );
778 i_height = qRound( (qreal) i_height / factor );
779 #endif
781 videoWidget->setSize( i_width, i_height );
786 /* Function that is CONNECTED to the previous emit */
787 void MainInterface::releaseVideoSlot( void )
789 /* This function is called when the embedded video window is destroyed,
790 * or in the rare case that the embedded window is still here but the
791 * Qt interface exits. */
792 assert( videoWidget );
793 videoWidget->release();
794 setVideoOnTop( false );
795 setVideoFullScreen( false );
796 hideResumePanel();
798 if( stackCentralW->currentWidget() == videoWidget )
799 restoreStackOldWidget( true );
800 else if( playlistWidget &&
801 playlistWidget->artContainer->currentWidget() == videoWidget )
803 playlistWidget->artContainer->setCurrentIndex( 0 );
804 stackCentralW->addWidget( videoWidget );
807 /* We don't want to have a blank video to popup */
808 stackCentralOldWidget = bgWidget;
811 // The provided size is in physical pixels, coming from the core.
812 void MainInterface::setVideoSize( unsigned int w, unsigned int h )
814 if (!isFullScreen() && !isMaximized() )
816 /* Resize video widget to video size, or keep it at the same
817 * size. Call setSize() either way so that vout_window_ReportSize
818 * will always get called.
819 * If the video size is too large for the screen, resize it
820 * to the screen size.
822 if (b_autoresize)
824 QRect screen = QApplication::desktop()->availableGeometry();
825 #if HAS_QT56
826 float factor = videoWidget->devicePixelRatioF();
827 #else
828 float factor = 1.0f;
829 #endif
830 if( (float)h / factor > screen.height() )
832 w = screen.width();
833 h = screen.height();
834 if( !b_minimalView )
836 if( menuBar()->isVisible() )
837 h -= menuBar()->height();
838 if( controls->isVisible() )
839 h -= controls->height();
840 if( statusBar()->isVisible() )
841 h -= statusBar()->height();
842 if( inputC->isVisible() )
843 h -= inputC->height();
845 h -= style()->pixelMetric(QStyle::PM_TitleBarHeight);
846 h -= style()->pixelMetric(QStyle::PM_LayoutBottomMargin);
847 h -= 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
849 else
851 // Convert the size in logical pixels
852 w = qRound( (float)w / factor );
853 h = qRound( (float)h / factor );
854 msg_Dbg( p_intf, "Logical video size: %ux%u", w, h );
856 videoWidget->setSize( w, h );
858 else
859 videoWidget->setSize( videoWidget->width(), videoWidget->height() );
863 void MainInterface::videoSizeChanged( int w, int h )
865 if( !playlistWidget || playlistWidget->artContainer->currentWidget() != videoWidget )
866 resizeStack( w, h );
869 void MainInterface::setVideoFullScreen( bool fs )
871 b_videoFullScreen = fs;
872 if( fs )
874 int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
876 if ( numscreen >= 0 && numscreen < QApplication::desktop()->screenCount() )
878 if( fullscreenControls )
879 fullscreenControls->setTargetScreen( numscreen );
881 QRect screenres = QApplication::desktop()->screenGeometry( numscreen );
882 lastWinScreen = windowHandle()->screen();
883 #ifdef QT5_HAS_WAYLAND
884 if( !b_hasWayland )
885 windowHandle()->setScreen(QGuiApplication::screens()[numscreen]);
886 #else
887 windowHandle()->setScreen(QGuiApplication::screens()[numscreen]);
888 #endif
890 /* To be sure window is on proper-screen in xinerama */
891 if( !screenres.contains( pos() ) )
893 lastWinPosition = pos();
894 lastWinSize = size();
895 msg_Dbg( p_intf, "Moving video to correct position");
896 move( QPoint( screenres.x(), screenres.y() ) );
900 if( playlistWidget != NULL && playlistWidget->artContainer->currentWidget() == videoWidget )
901 showTab( videoWidget );
903 /* we won't be able to get its windowed sized once in fullscreen, so update it now */
904 stackWidgetsSizes[stackCentralW->currentWidget()] = stackCentralW->size();
906 /* */
907 displayNormalView();
908 setInterfaceFullScreen( true );
910 else
912 setMinimalView( b_minimalView );
913 setInterfaceFullScreen( b_interfaceFullScreen );
914 #ifdef QT5_HAS_WAYLAND
915 if( lastWinScreen != NULL && !b_hasWayland )
916 windowHandle()->setScreen(lastWinScreen);
917 #else
918 if( lastWinScreen != NULL )
919 windowHandle()->setScreen(lastWinScreen);
920 #endif
921 if( lastWinPosition.isNull() == false )
923 move( lastWinPosition );
924 lastWinPosition = QPoint();
925 if( !pendingResize.isValid() )
927 resizeWindow( lastWinSize.width(), lastWinSize.height() );
928 lastWinSize = QSize();
931 if( pendingResize.isValid() )
933 /* apply resize requested while fullscreen was enabled */
934 resizeStack( pendingResize.width(), pendingResize.height() );
935 pendingResize = QSize(); // consume
939 videoWidget->sync();
942 /* Slot to change the video always-on-top flag.
943 * Emit askVideoOnTop() to invoke this from other thread. */
944 void MainInterface::setVideoOnTop( bool on_top )
946 //don't apply changes if user has already sets its interface on top
947 if ( b_interfaceOnTop )
948 return;
950 Qt::WindowFlags oldflags = windowFlags(), newflags;
952 if( on_top )
953 newflags = oldflags | Qt::WindowStaysOnTopHint;
954 else
955 newflags = oldflags & ~Qt::WindowStaysOnTopHint;
956 if( newflags != oldflags && !b_videoFullScreen )
958 setWindowFlags( newflags );
959 show(); /* necessary to apply window flags */
963 void MainInterface::setInterfaceAlwaysOnTop( bool on_top )
965 b_interfaceOnTop = on_top;
966 Qt::WindowFlags oldflags = windowFlags(), newflags;
968 if( on_top )
969 newflags = oldflags | Qt::WindowStaysOnTopHint;
970 else
971 newflags = oldflags & ~Qt::WindowStaysOnTopHint;
972 if( newflags != oldflags && !b_videoFullScreen )
974 setWindowFlags( newflags );
975 show(); /* necessary to apply window flags */
979 /* Asynchronous calls for video window contrlos */
980 int MainInterface::enableVideo( vout_window_t *p_wnd,
981 const vout_window_cfg_t *cfg )
983 MainInterface *p_mi = (MainInterface *)p_wnd->sys;
985 msg_Dbg( p_wnd, "requesting video window..." );
986 /* This is a blocking call signal. Results are stored directly in the
987 * vout_window_t and boolean pointers. Beware of deadlocks! */
988 emit p_mi->askGetVideo( p_wnd, cfg->width, cfg->height,
989 cfg->is_fullscreen );
990 return VLC_SUCCESS;
993 void MainInterface::disableVideo( vout_window_t *p_wnd )
995 MainInterface *p_mi = (MainInterface *)p_wnd->sys;
997 msg_Dbg( p_wnd, "releasing video..." );
998 emit p_mi->askReleaseVideo();
1001 void MainInterface::resizeVideo( vout_window_t *p_wnd,
1002 unsigned i_width, unsigned i_height )
1004 MainInterface *p_mi = (MainInterface *)p_wnd->sys;
1006 emit p_mi->askVideoToResize( i_width, i_height );
1009 void MainInterface::requestVideoWindowed( struct vout_window_t *wnd )
1011 MainInterface *p_mi = (MainInterface *)wnd->sys;
1013 emit p_mi->askVideoSetFullScreen( false );
1016 void MainInterface::requestVideoFullScreen( vout_window_t *wnd, const char * )
1018 MainInterface *p_mi = (MainInterface *)wnd->sys;
1020 emit p_mi->askVideoSetFullScreen( true );
1023 void MainInterface::requestVideoState( vout_window_t *p_wnd, unsigned i_arg )
1025 MainInterface *p_mi = (MainInterface *)p_wnd->sys;
1026 bool on_top = (i_arg & VOUT_WINDOW_STATE_ABOVE) != 0;
1028 emit p_mi->askVideoOnTop( on_top );
1031 void MainInterface::releaseVideo( vout_window_t *p_wnd )
1033 MainInterface *p_mi = (MainInterface *)p_wnd->sys;
1035 /* Releasing video (in disableVideo()) was a blocking call.
1036 * The video is no longer active by this point.
1038 p_mi->videoActive.clear();
1041 /*****************************************************************************
1042 * Playlist, Visualisation and Menus handling
1043 *****************************************************************************/
1045 * Toggle the playlist widget or dialog
1047 void MainInterface::createPlaylist()
1049 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
1051 if( b_plDocked )
1053 playlistWidget = dialog->exportPlaylistWidget();
1054 stackCentralW->addWidget( playlistWidget );
1055 stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 600, 300 ) ).toSize();
1057 CONNECT( dialog, visibilityChanged(bool), this, setPlaylistVisibility(bool) );
1060 void MainInterface::togglePlaylist()
1062 if( !playlistWidget ) createPlaylist();
1064 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
1065 if( b_plDocked )
1067 if ( dialog->hasPlaylistWidget() )
1068 playlistWidget = dialog->exportPlaylistWidget();
1069 /* Playlist is not visible, show it */
1070 if( stackCentralW->currentWidget() != playlistWidget )
1072 if( stackCentralW->indexOf( playlistWidget ) == -1 )
1073 stackCentralW->addWidget( playlistWidget );
1074 showTab( playlistWidget );
1076 else /* Hide it! */
1078 restoreStackOldWidget();
1080 playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
1082 else
1084 playlistVisible = !playlistVisible;
1085 if ( ! dialog->hasPlaylistWidget() )
1086 dialog->importPlaylistWidget( playlistWidget );
1087 if ( playlistVisible )
1088 dialog->show();
1089 else
1090 dialog->hide();
1092 debug();
1095 const Qt::Key MainInterface::kc[10] =
1097 Qt::Key_Up, Qt::Key_Up,
1098 Qt::Key_Down, Qt::Key_Down,
1099 Qt::Key_Left, Qt::Key_Right, Qt::Key_Left, Qt::Key_Right,
1100 Qt::Key_B, Qt::Key_A
1103 void MainInterface::dockPlaylist( bool p_docked )
1105 if( b_plDocked == p_docked ) return;
1106 /* some extra check */
1107 if ( b_plDocked && !playlistWidget ) createPlaylist();
1109 b_plDocked = p_docked;
1110 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
1112 if( !p_docked ) /* Previously docked */
1114 playlistVisible = playlistWidget->isVisible();
1116 /* repositioning the videowidget __before__ exporting the
1117 playlistwidget into the playlist dialog avoids two unneeded
1118 calls to the server in the qt library to reparent the underlying
1119 native window back and forth.
1120 For Wayland, this is mandatory since reparenting is not implemented.
1121 For X11 or Windows, this is just an optimization. */
1122 if ( videoWidget && THEMIM->getIM()->hasVideo() )
1123 showTab(videoWidget);
1124 else
1125 showTab(bgWidget);
1127 /* playlistwidget exported into the playlist dialog */
1128 stackCentralW->removeWidget( playlistWidget );
1129 dialog->importPlaylistWidget( playlistWidget );
1130 if ( playlistVisible ) dialog->show();
1132 else /* Previously undocked */
1134 playlistVisible = dialog->isVisible() && !( videoWidget && THEMIM->getIM()->hasVideo() );
1135 dialog->hide();
1136 playlistWidget = dialog->exportPlaylistWidget();
1137 stackCentralW->addWidget( playlistWidget );
1139 /* If playlist is invisible don't show it */
1140 if( playlistVisible ) showTab( playlistWidget );
1145 * displayNormalView is the private function used by
1146 * the SLOT setVideoFullScreen to restore the menuBar
1147 * if minimal view is off
1149 void MainInterface::displayNormalView()
1151 menuBar()->setVisible( false );
1152 controls->setVisible( false );
1153 statusBar()->setVisible( false );
1154 inputC->setVisible( false );
1158 * setMinimalView is the private function used by
1159 * the SLOT toggleMinimalView
1161 void MainInterface::setMinimalView( bool b_minimal )
1163 bool b_menuBarVisible = menuBar()->isVisible();
1164 bool b_controlsVisible = controls->isVisible();
1165 bool b_statusBarVisible = statusBar()->isVisible();
1166 bool b_inputCVisible = inputC->isVisible();
1168 if( !isFullScreen() && !isMaximized() && b_minimal && !b_isWindowTiled )
1170 int i_heightChange = 0;
1172 if( b_menuBarVisible )
1173 i_heightChange += menuBar()->height();
1174 if( b_controlsVisible )
1175 i_heightChange += controls->height();
1176 if( b_statusBarVisible )
1177 i_heightChange += statusBar()->height();
1178 if( b_inputCVisible )
1179 i_heightChange += inputC->height();
1181 if( i_heightChange != 0 )
1182 resizeWindow( width(), height() - i_heightChange );
1185 menuBar()->setVisible( !b_minimal );
1186 controls->setVisible( !b_minimal );
1187 statusBar()->setVisible( !b_minimal && b_statusbarVisible );
1188 inputC->setVisible( !b_minimal );
1190 if( !isFullScreen() && !isMaximized() && !b_minimal && !b_isWindowTiled )
1192 int i_heightChange = 0;
1194 if( !b_menuBarVisible && menuBar()->isVisible() )
1195 i_heightChange += menuBar()->height();
1196 if( !b_controlsVisible && controls->isVisible() )
1197 i_heightChange += controls->height();
1198 if( !b_statusBarVisible && statusBar()->isVisible() )
1199 i_heightChange += statusBar()->height();
1200 if( !b_inputCVisible && inputC->isVisible() )
1201 i_heightChange += inputC->height();
1203 if( i_heightChange != 0 )
1204 resizeWindow( width(), height() + i_heightChange );
1209 * This public SLOT is used for moving to minimal View Mode
1211 * If b_minimal is false, then we are normalView
1213 void MainInterface::toggleMinimalView( bool b_minimal )
1215 if( !b_minimalView && b_autoresize ) /* Normal mode */
1217 if( stackCentralW->currentWidget() == bgWidget )
1219 if( stackCentralW->height() < 16 )
1221 resizeStack( stackCentralW->width(), 100 );
1225 b_minimalView = b_minimal;
1226 if( !b_videoFullScreen )
1228 setMinimalView( b_minimalView );
1229 computeMinimumSize();
1232 emit minimalViewToggled( b_minimalView );
1235 /* toggling advanced controls buttons */
1236 void MainInterface::toggleAdvancedButtons()
1238 controls->toggleAdvanced();
1239 // if( fullscreenControls ) fullscreenControls->toggleAdvanced();
1242 /* Get the visibility status of the controls (hidden or not, advanced or not) */
1243 int MainInterface::getControlsVisibilityStatus()
1245 if( !controls ) return 0;
1246 return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
1247 + CONTROLS_ADVANCED * controls->b_advancedVisible );
1250 StandardPLPanel *MainInterface::getPlaylistView()
1252 if( !playlistWidget ) return NULL;
1253 else return playlistWidget->mainView;
1256 void MainInterface::setStatusBarVisibility( bool b_visible )
1258 statusBar()->setVisible( b_visible );
1259 b_statusbarVisible = b_visible;
1260 if( controls ) controls->setGripVisible( !b_statusbarVisible );
1264 void MainInterface::setPlaylistVisibility( bool b_visible )
1266 if( isPlDocked() || THEDP->isDying() || (playlistWidget && playlistWidget->isMinimized() ) )
1267 return;
1269 playlistVisible = b_visible;
1272 /************************************************************************
1273 * Other stuff
1274 ************************************************************************/
1275 void MainInterface::setName( const QString& name )
1277 input_name = name; /* store it for the QSystray use */
1278 /* Display it in the status bar, but also as a Tooltip in case it doesn't
1279 fit in the label */
1280 nameLabel->setText( name );
1281 nameLabel->setToolTip( name );
1285 * Give the decorations of the Main Window a correct Name.
1286 * If nothing is given, set it to VLC...
1288 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
1290 if( aTitle.isEmpty() )
1292 setWindowTitle( qtr( "VLC media player" ) );
1294 else
1296 setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
1300 void MainInterface::showCryptedLabel( bool b_show )
1302 if( cryptedLabel == NULL )
1304 cryptedLabel = new QLabel;
1305 // The lock icon is not the right one for DRM protection/scrambled.
1306 //cryptedLabel->setPixmap( QPixmap( ":/lock.svg" ) );
1307 cryptedLabel->setText( "DRM" );
1308 statusBar()->addWidget( cryptedLabel );
1311 cryptedLabel->setVisible( b_show );
1314 void MainInterface::showBuffering( float f_cache )
1316 QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
1317 statusBar()->showMessage( amount, 1000 );
1320 /*****************************************************************************
1321 * Systray Icon and Systray Menu
1322 *****************************************************************************/
1324 * Create a SystemTray icon and a menu that would go with it.
1325 * Connects to a click handler on the icon.
1327 void MainInterface::createSystray()
1329 QIcon iconVLC;
1330 if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
1331 iconVLC = QIcon::fromTheme( "vlc-xmas", QIcon( ":/logo/vlc128-xmas.png" ) );
1332 else
1333 iconVLC = QIcon::fromTheme( "vlc", QIcon( ":/logo/vlc256.png" ) );
1334 sysTray = new QSystemTrayIcon( iconVLC, this );
1335 sysTray->setToolTip( qtr( "VLC media player" ));
1337 systrayMenu = new QMenu( qtr( "VLC media player" ), this );
1338 systrayMenu->setIcon( iconVLC );
1340 VLCMenuBar::updateSystrayMenu( this, p_intf, true );
1341 sysTray->show();
1343 CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
1344 this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
1346 /* Connects on nameChanged() */
1347 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
1348 this, updateSystrayTooltipName( const QString& ) );
1349 /* Connect PLAY_STATUS on the systray */
1350 CONNECT( THEMIM->getIM(), playingStatusChanged( int ),
1351 this, updateSystrayTooltipStatus( int ) );
1354 void MainInterface::toggleUpdateSystrayMenuWhenVisible()
1356 hide();
1359 void MainInterface::resizeWindow(int w, int h)
1361 #if ! HAS_QT510 && defined(QT5_HAS_X11)
1362 if( QX11Info::isPlatformX11() )
1364 #if HAS_QT56
1365 qreal dpr = devicePixelRatioF();
1366 #else
1367 qreal dpr = devicePixelRatio();
1368 #endif
1369 QSize size(w, h);
1370 size = size.boundedTo(maximumSize()).expandedTo(minimumSize());
1371 /* X11 window managers are not required to accept geometry changes on
1372 * the top-level window. Unfortunately, Qt < 5.10 assumes that the
1373 * change will succeed, and resizes all sub-windows unconditionally.
1374 * By calling XMoveResizeWindow directly, Qt will not see our change
1375 * request until the ConfigureNotify event on success
1376 * and not at all if it is rejected. */
1377 XResizeWindow( QX11Info::display(), winId(),
1378 (unsigned int)size.width() * dpr, (unsigned int)size.height() * dpr);
1379 return;
1381 #endif
1382 resize(w, h);
1386 * Updates the Systray Icon's menu and toggle the main interface
1388 void MainInterface::toggleUpdateSystrayMenu()
1390 /* If hidden, show it */
1391 if( isHidden() )
1393 show();
1394 activateWindow();
1396 else if( isMinimized() )
1398 /* Minimized */
1399 showNormal();
1400 activateWindow();
1402 else
1404 /* Visible (possibly under other windows) */
1405 toggleUpdateSystrayMenuWhenVisible();
1407 if( sysTray )
1408 VLCMenuBar::updateSystrayMenu( this, p_intf );
1411 /* First Item of the systray menu */
1412 void MainInterface::showUpdateSystrayMenu()
1414 if( isHidden() )
1415 show();
1416 if( isMinimized() )
1417 showNormal();
1418 activateWindow();
1420 VLCMenuBar::updateSystrayMenu( this, p_intf );
1423 /* First Item of the systray menu */
1424 void MainInterface::hideUpdateSystrayMenu()
1426 hide();
1427 VLCMenuBar::updateSystrayMenu( this, p_intf );
1430 /* Click on systray Icon */
1431 void MainInterface::handleSystrayClick(
1432 QSystemTrayIcon::ActivationReason reason )
1434 switch( reason )
1436 case QSystemTrayIcon::Trigger:
1437 case QSystemTrayIcon::DoubleClick:
1438 #ifdef Q_OS_MAC
1439 VLCMenuBar::updateSystrayMenu( this, p_intf );
1440 #else
1441 toggleUpdateSystrayMenu();
1442 #endif
1443 break;
1444 case QSystemTrayIcon::MiddleClick:
1445 sysTray->showMessage( qtr( "VLC media player" ),
1446 qtr( "Control menu for the player" ),
1447 QSystemTrayIcon::Information, 3000 );
1448 break;
1449 default:
1450 break;
1455 * Updates the name of the systray Icon tooltip.
1456 * Doesn't check if the systray exists, check before you call it.
1458 void MainInterface::updateSystrayTooltipName( const QString& name )
1460 if( name.isEmpty() )
1462 sysTray->setToolTip( qtr( "VLC media player" ) );
1464 else
1466 sysTray->setToolTip( name );
1467 if( ( i_notificationSetting == NOTIFICATION_ALWAYS ) ||
1468 ( i_notificationSetting == NOTIFICATION_MINIMIZED && (isMinimized() || isHidden()) ) )
1470 sysTray->showMessage( qtr( "VLC media player" ), name,
1471 QSystemTrayIcon::NoIcon, 3000 );
1475 VLCMenuBar::updateSystrayMenu( this, p_intf );
1479 * Updates the status of the systray Icon tooltip.
1480 * Doesn't check if the systray exists, check before you call it.
1482 void MainInterface::updateSystrayTooltipStatus( int i_status )
1484 switch( i_status )
1486 case PLAYING_S:
1487 sysTray->setToolTip( input_name );
1488 break;
1489 case PAUSE_S:
1490 sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1491 break;
1492 default:
1493 sysTray->setToolTip( qtr( "VLC media player" ) );
1494 break;
1496 VLCMenuBar::updateSystrayMenu( this, p_intf );
1499 void MainInterface::changeEvent(QEvent *event)
1501 if( event->type() == QEvent::WindowStateChange )
1503 QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
1504 Qt::WindowStates newState = windowState();
1505 Qt::WindowStates oldState = windowStateChangeEvent->oldState();
1507 /* b_maximizedView stores if the window was maximized before entering fullscreen.
1508 * It is set when entering maximized mode, unset when leaving it to normal mode.
1509 * Upon leaving full screen, if b_maximizedView is set,
1510 * the window should be maximized again. */
1511 if( newState & Qt::WindowMaximized &&
1512 !( oldState & Qt::WindowMaximized ) )
1513 b_maximizedView = true;
1515 if( !( newState & Qt::WindowMaximized ) &&
1516 oldState & Qt::WindowMaximized &&
1517 !b_videoFullScreen )
1518 b_maximizedView = false;
1520 if( !( newState & Qt::WindowFullScreen ) &&
1521 oldState & Qt::WindowFullScreen &&
1522 b_maximizedView )
1524 showMaximized();
1525 return;
1528 if( newState & Qt::WindowMinimized )
1530 b_hasPausedWhenMinimized = false;
1532 if( THEMIM->getIM()->playingStatus() == PLAYING_S &&
1533 THEMIM->getIM()->hasVideo() && !THEMIM->getIM()->hasVisualisation() &&
1534 b_pauseOnMinimize )
1536 b_hasPausedWhenMinimized = true;
1537 THEMIM->pause();
1540 else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
1542 if( b_hasPausedWhenMinimized )
1544 THEMIM->play();
1549 QWidget::changeEvent(event);
1552 /************************************************************************
1553 * D&D Events
1554 ************************************************************************/
1555 void MainInterface::dropEvent(QDropEvent *event)
1557 dropEventPlay( event, true );
1561 * dropEventPlay
1563 * Event called if something is dropped onto a VLC window
1564 * \param event the event in question
1565 * \param b_play whether to play the file immediately
1566 * \return nothing
1568 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play )
1570 if( event->possibleActions() & ( Qt::CopyAction | Qt::MoveAction | Qt::LinkAction ) )
1571 event->setDropAction( Qt::CopyAction );
1572 else
1573 return;
1575 const QMimeData *mimeData = event->mimeData();
1577 /* D&D of a subtitles file, add it on the fly */
1578 if( mimeData->urls().count() == 1 && THEMIM->getIM()->hasInput() )
1580 if( !input_AddSlave( THEMIM->getInput(), SLAVE_TYPE_SPU,
1581 qtu( mimeData->urls()[0].toString() ), true, true, true ) )
1583 event->accept();
1584 return;
1588 bool first = b_play;
1589 foreach( const QUrl &url, mimeData->urls() )
1591 if( url.isValid() )
1593 QString mrl = toURI( url.toEncoded().constData() );
1594 #ifdef _WIN32
1595 QFileInfo info( url.toLocalFile() );
1596 if( info.exists() && info.isSymLink() )
1598 QString target = info.symLinkTarget();
1599 QUrl url;
1600 if( QFile::exists( target ) )
1602 url = QUrl::fromLocalFile( target );
1604 else
1606 url.setUrl( target );
1608 mrl = toURI( url.toEncoded().constData() );
1610 #endif
1611 if( mrl.length() > 0 )
1613 Open::openMRL( p_intf, mrl, first );
1614 first = false;
1619 /* Browsers give content as text if you dnd the addressbar,
1620 so check if mimedata has valid url in text and use it
1621 if we didn't get any normal Urls()*/
1622 if( !mimeData->hasUrls() && mimeData->hasText() &&
1623 QUrl(mimeData->text()).isValid() )
1625 QString mrl = toURI( mimeData->text() );
1626 Open::openMRL( p_intf, mrl, first );
1628 event->accept();
1630 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1632 event->acceptProposedAction();
1634 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1636 event->acceptProposedAction();
1638 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1640 event->accept();
1643 /************************************************************************
1644 * Events stuff
1645 ************************************************************************/
1646 void MainInterface::keyPressEvent( QKeyEvent *e )
1648 handleKeyPress( e );
1650 /* easter eggs sequence handling */
1651 if ( e->key() == kc[ i_kc_offset ] )
1652 i_kc_offset++;
1653 else
1654 i_kc_offset = 0;
1656 if ( i_kc_offset == (sizeof( kc ) / sizeof( Qt::Key )) )
1658 i_kc_offset = 0;
1659 emit kc_pressed();
1663 void MainInterface::handleKeyPress( QKeyEvent *e )
1665 if( ( ( e->modifiers() & Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) ) ||
1666 ( b_minimalView && !b_videoFullScreen && e->key() == Qt::Key_Escape ) )
1668 toggleMinimalView( !b_minimalView );
1669 e->accept();
1671 else if( ( e->modifiers() & Qt::ControlModifier ) && ( e->key() == Qt::Key_K ) &&
1672 playlistWidget )
1674 playlistWidget->setSearchFieldFocus();
1675 e->accept();
1678 int i_vlck = qtEventToVLCKey( e );
1679 if( i_vlck > 0 )
1681 var_SetInteger( p_intf->obj.libvlc, "key-pressed", i_vlck );
1682 e->accept();
1684 else
1685 e->ignore();
1688 void MainInterface::wheelEvent( QWheelEvent *e )
1690 int i_vlckey = qtWheelEventToVLCKey( e );
1691 var_SetInteger( p_intf->obj.libvlc, "key-pressed", i_vlckey );
1692 e->accept();
1695 void MainInterface::closeEvent( QCloseEvent *e )
1697 // hide();
1698 if ( b_minimalView )
1699 setMinimalView( false );
1700 emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
1701 /* Accept session quit. Otherwise we break the desktop mamager. */
1702 e->accept();
1705 bool MainInterface::eventFilter( QObject *obj, QEvent *event )
1707 if ( event->type() == MainInterface::ToolbarsNeedRebuild ) {
1708 event->accept();
1709 recreateToolbars();
1710 return true;
1711 } else {
1712 return QObject::eventFilter( obj, event );
1716 void MainInterface::toolBarConfUpdated()
1718 QApplication::postEvent( this, new QEvent( MainInterface::ToolbarsNeedRebuild ) );
1721 void MainInterface::setInterfaceFullScreen( bool fs )
1723 if( fs )
1724 setWindowState( windowState() | Qt::WindowFullScreen );
1725 else
1726 setWindowState( windowState() & ~Qt::WindowFullScreen );
1728 void MainInterface::toggleInterfaceFullScreen()
1730 b_interfaceFullScreen = !b_interfaceFullScreen;
1731 if( !b_videoFullScreen )
1732 setInterfaceFullScreen( b_interfaceFullScreen );
1733 emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1736 void MainInterface::emitBoss()
1738 emit askBoss();
1740 void MainInterface::setBoss()
1742 THEMIM->pause();
1743 if( sysTray )
1745 hide();
1747 else
1749 showMinimized();
1753 void MainInterface::emitRaise()
1755 emit askRaise();
1757 void MainInterface::setRaise()
1759 activateWindow();
1760 raise();
1763 void MainInterface::voutReleaseMouseEvents()
1765 if (videoWidget)
1767 QPoint pos = QCursor::pos();
1768 QPoint localpos = videoWidget->mapFromGlobal(pos);
1769 int buttons = QApplication::mouseButtons();
1770 int i_button = 1;
1771 while (buttons != 0)
1773 if ( (buttons & 1) != 0 )
1775 QMouseEvent new_e( QEvent::MouseButtonRelease, localpos,
1776 (Qt::MouseButton)i_button, (Qt::MouseButton)i_button, Qt::NoModifier );
1777 QApplication::sendEvent(videoWidget, &new_e);
1779 buttons >>= 1;
1780 i_button <<= 1;
1786 /*****************************************************************************
1787 * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1788 * We don't show the menu directly here because we don't want the
1789 * caller to block for a too long time.
1790 *****************************************************************************/
1791 static int PopupMenuCB( vlc_object_t *, const char *,
1792 vlc_value_t, vlc_value_t new_val, void *param )
1794 intf_thread_t *p_intf = (intf_thread_t *)param;
1796 if( p_intf->pf_show_dialog )
1798 p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1799 new_val.b_bool, NULL );
1802 return VLC_SUCCESS;
1805 /*****************************************************************************
1806 * IntfShowCB: callback triggered by the intf-toggle-fscontrol libvlc variable.
1807 *****************************************************************************/
1808 static int IntfShowCB( vlc_object_t *, const char *,
1809 vlc_value_t, vlc_value_t, void *param )
1811 intf_thread_t *p_intf = (intf_thread_t *)param;
1812 p_intf->p_sys->p_mi->toggleFSC();
1814 /* Show event */
1815 return VLC_SUCCESS;
1818 /*****************************************************************************
1819 * IntfRaiseMainCB: callback triggered by the intf-show-main libvlc variable.
1820 *****************************************************************************/
1821 static int IntfRaiseMainCB( vlc_object_t *, const char *,
1822 vlc_value_t, vlc_value_t, void *param )
1824 intf_thread_t *p_intf = (intf_thread_t *)param;
1825 p_intf->p_sys->p_mi->emitRaise();
1827 return VLC_SUCCESS;
1830 /*****************************************************************************
1831 * IntfBossCB: callback triggered by the intf-boss libvlc variable.
1832 *****************************************************************************/
1833 static int IntfBossCB( vlc_object_t *, const char *,
1834 vlc_value_t, vlc_value_t, void *param )
1836 intf_thread_t *p_intf = (intf_thread_t *)param;
1837 p_intf->p_sys->p_mi->emitBoss();
1839 return VLC_SUCCESS;