qt: add device preferences for mmdevice
[vlc.git] / modules / gui / qt / main_interface.cpp
blob35e46ece208bd7892848f81d82b064508ba86099
1 /*****************************************************************************
2 * main_interface.cpp : Main interface
3 ****************************************************************************
4 * Copyright (C) 2006-2011 VideoLAN and AUTHORS
5 * $Id$
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 *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include "qt.hpp"
32 #include "main_interface.hpp"
33 #include "input_manager.hpp" // Creation
34 #include "actions_manager.hpp" // killInstance
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_display.h> /* vout_thread_t and 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 )
96 /* Variables initialisation */
97 bgWidget = NULL;
98 videoWidget = NULL;
99 playlistWidget = NULL;
100 stackCentralOldWidget= NULL;
101 lastWinScreen = NULL;
102 sysTray = NULL;
103 fullscreenControls = NULL;
104 cryptedLabel = NULL;
105 controls = NULL;
106 inputC = NULL;
108 b_hideAfterCreation = false; // --qt-start-minimized
109 playlistVisible = false;
110 input_name = "";
111 b_interfaceFullScreen= false;
112 b_hasPausedWhenMinimized = false;
113 i_kc_offset = false;
114 b_maximizedView = false;
115 b_isWindowTiled = false;
117 /* Ask for Privacy */
118 FirstRun::CheckAndRun( this, p_intf );
121 * Configuration and settings
122 * Pre-building of interface
124 /* Main settings */
125 setFocusPolicy( Qt::StrongFocus );
126 setAcceptDrops( true );
127 setWindowRole( "vlc-main" );
128 setWindowIcon( QApplication::windowIcon() );
129 setWindowOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
131 /* Does the interface resize to video size or the opposite */
132 b_autoresize = var_InheritBool( p_intf, "qt-video-autoresize" );
134 /* Are we in the enhanced always-video mode or not ? */
135 b_minimalView = var_InheritBool( p_intf, "qt-minimal-view" );
137 /* Do we want anoying popups or not */
138 i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
140 /* */
141 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
143 /* Set the other interface settings */
144 settings = getSettings();
146 /* */
147 b_plDocked = getSettings()->value( "MainWindow/pl-dock-status", true ).toBool();
149 /* Should the UI stays on top of other windows */
150 b_interfaceOnTop = var_InheritBool( p_intf, "video-on-top" );
152 #ifdef QT5_HAS_WAYLAND
153 b_hasWayland = QGuiApplication::platformName()
154 .startsWith(QLatin1String("wayland"), Qt::CaseInsensitive);
155 #endif
157 /**************************
158 * UI and Widgets design
159 **************************/
160 setVLCWindowsTitle();
162 /************
163 * Menu Bar *
164 ************/
165 VLCMenuBar::createMenuBar( this, p_intf );
166 CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
167 THEDP, destroyPopupMenu() );
169 createMainWidget( settings );
171 /**************
172 * Status Bar *
173 **************/
174 createStatusBar();
175 setStatusBarVisibility( getSettings()->value( "MainWindow/status-bar-visible", false ).toBool() );
177 /*********************************
178 * Create the Systray Management *
179 *********************************/
180 initSystray();
182 /*************************************************************
183 * Connect the input manager to the GUI elements it manages *
184 * Beware initSystray did some connects on input manager too *
185 *************************************************************/
187 * Connects on nameChanged()
188 * Those connects are different because options can impeach them to trigger.
190 /* Main Interface statusbar */
191 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
192 this, setName( const QString& ) );
193 /* and title of the Main Interface*/
194 if( var_InheritBool( p_intf, "qt-name-in-title" ) )
196 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
197 this, setVLCWindowsTitle( const QString& ) );
199 CONNECT( THEMIM, inputChanged( bool ), this, onInputChanged( bool ) );
201 /* END CONNECTS ON IM */
203 /* VideoWidget connects for asynchronous calls */
204 b_videoFullScreen = false;
205 connect( this, SIGNAL(askGetVideo(struct vout_window_t*, unsigned, unsigned, bool, bool*)),
206 this, SLOT(getVideoSlot(struct vout_window_t*, unsigned, unsigned, bool, bool*)),
207 Qt::BlockingQueuedConnection );
208 connect( this, SIGNAL(askReleaseVideo( void )),
209 this, SLOT(releaseVideoSlot( void )),
210 Qt::BlockingQueuedConnection );
211 CONNECT( this, askVideoOnTop(bool), this, setVideoOnTop(bool));
213 if( videoWidget )
215 if( b_autoresize )
217 CONNECT( videoWidget, sizeChanged( int, int ),
218 this, videoSizeChanged( int, int ) );
220 CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
221 this, setVideoSize( unsigned int, unsigned int ) );
223 CONNECT( this, askVideoSetFullScreen( bool ),
224 this, setVideoFullScreen( bool ) );
225 CONNECT( this, askHideMouse( bool ),
226 this, setHideMouse( bool ) );
229 CONNECT( THEDP, toolBarConfUpdated(), this, toolBarConfUpdated() );
230 installEventFilter( this );
232 CONNECT( this, askToQuit(), THEDP, quit() );
234 CONNECT( this, askBoss(), this, setBoss() );
235 CONNECT( this, askRaise(), this, setRaise() );
238 connect( THEDP, &DialogsProvider::releaseMouseEvents, this, &MainInterface::voutReleaseMouseEvents ) ;
239 /** END of CONNECTS**/
242 /************
243 * Callbacks
244 ************/
245 var_AddCallback( p_intf->obj.libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
246 var_AddCallback( p_intf->obj.libvlc, "intf-boss", IntfBossCB, p_intf );
247 var_AddCallback( p_intf->obj.libvlc, "intf-show", IntfRaiseMainCB, p_intf );
249 /* Register callback for the intf-popupmenu variable */
250 var_AddCallback( p_intf->obj.libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
253 /* Final Sizing, restoration and placement of the interface */
254 if( settings->value( "MainWindow/playlist-visible", false ).toBool() )
255 togglePlaylist();
257 QVLCTools::restoreWidgetPosition( settings, this, QSize(600, 420) );
259 b_interfaceFullScreen = isFullScreen();
261 setVisible( !b_hideAfterCreation );
263 /* Switch to minimal view if needed, must be called after the show() */
264 if( b_minimalView )
265 toggleMinimalView( true );
267 computeMinimumSize();
270 MainInterface::~MainInterface()
272 /* Unsure we hide the videoWidget before destroying it */
273 if( stackCentralOldWidget == videoWidget )
274 showTab( bgWidget );
276 if( videoWidget )
277 releaseVideoSlot();
279 /* Be sure to kill the actionsManager... Only used in the MI and control */
280 ActionsManager::killInstance();
282 /* Delete the FSC controller */
283 delete fullscreenControls;
285 /* Save states */
287 settings->beginGroup("MainWindow");
288 settings->setValue( "pl-dock-status", b_plDocked );
290 /* Save playlist state */
291 settings->setValue( "playlist-visible", playlistVisible );
293 settings->setValue( "adv-controls",
294 getControlsVisibilityStatus() & CONTROLS_ADVANCED );
295 settings->setValue( "status-bar-visible", b_statusbarVisible );
297 /* Save the stackCentralW sizes */
298 settings->setValue( "bgSize", stackWidgetsSizes[bgWidget] );
299 settings->setValue( "playlistSize", stackWidgetsSizes[playlistWidget] );
300 settings->endGroup();
302 /* Save this size */
303 QVLCTools::saveWidgetPosition(settings, this);
305 /* Unregister callbacks */
306 var_DelCallback( p_intf->obj.libvlc, "intf-boss", IntfBossCB, p_intf );
307 var_DelCallback( p_intf->obj.libvlc, "intf-show", IntfRaiseMainCB, p_intf );
308 var_DelCallback( p_intf->obj.libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
309 var_DelCallback( p_intf->obj.libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
311 p_intf->p_sys->p_mi = NULL;
314 void MainInterface::computeMinimumSize()
316 int minWidth = 80;
317 if( menuBar()->isVisible() )
318 minWidth += controls->sizeHint().width();
320 setMinimumWidth( minWidth );
323 /*****************************
324 * Main UI handling *
325 *****************************/
326 void MainInterface::recreateToolbars()
328 bool b_adv = getControlsVisibilityStatus() & CONTROLS_ADVANCED;
330 delete controls;
331 delete inputC;
333 controls = new ControlsWidget( p_intf, b_adv, this );
334 inputC = new InputControlsWidget( p_intf, this );
335 mainLayout->insertWidget( 2, inputC );
336 mainLayout->insertWidget( settings->value( "MainWindow/ToolbarPos", false ).toBool() ? 0: 3,
337 controls );
339 if( fullscreenControls )
341 delete fullscreenControls;
342 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
343 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
344 this, handleKeyPress( QKeyEvent * ) );
345 THEMIM->requestVoutUpdate();
348 setMinimalView( b_minimalView );
351 void MainInterface::reloadPrefs()
353 i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
354 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
355 if( !var_InheritBool( p_intf, "qt-fs-controller" ) && fullscreenControls )
357 delete fullscreenControls;
358 fullscreenControls = NULL;
362 void MainInterface::createResumePanel( QWidget *w )
364 resumePanel = new QWidget( w );
365 resumePanel->hide();
366 QHBoxLayout *resumePanelLayout = new QHBoxLayout( resumePanel );
367 resumePanelLayout->setSpacing( 0 ); resumePanelLayout->setMargin( 0 );
369 QLabel *continuePixmapLabel = new QLabel();
370 continuePixmapLabel->setPixmap( ImageHelper::loadSvgToPixmap( ":/menu/help.svg" , fontMetrics().height(), fontMetrics().height()) );
371 continuePixmapLabel->setContentsMargins( 5, 0, 5, 0 );
373 QLabel *continueLabel = new QLabel( qtr( "Do you want to restart the playback where left off?") );
375 QToolButton *cancel = new QToolButton( resumePanel );
376 cancel->setAutoRaise( true );
377 cancel->setText( "X" );
379 QPushButton *ok = new QPushButton( qtr( "&Continue" ) );
381 resumePanelLayout->addWidget( continuePixmapLabel );
382 resumePanelLayout->addWidget( continueLabel );
383 resumePanelLayout->addStretch( 1 );
384 resumePanelLayout->addWidget( ok );
385 resumePanelLayout->addWidget( cancel );
387 resumeTimer = new QTimer( resumePanel );
388 resumeTimer->setSingleShot( true );
389 resumeTimer->setInterval( 6000 );
391 CONNECT( resumeTimer, timeout(), this, hideResumePanel() );
392 CONNECT( cancel, clicked(), this, hideResumePanel() );
393 CONNECT( THEMIM->getIM(), resumePlayback(int64_t), this, showResumePanel(int64_t) );
394 BUTTONACT( ok, resumePlayback() );
396 w->layout()->addWidget( resumePanel );
399 void MainInterface::showResumePanel( int64_t _time ) {
400 int setting = var_InheritInteger( p_intf, "qt-continue" );
402 if( setting == 0 )
403 return;
405 i_resumeTime = _time;
407 if( setting == 2)
408 resumePlayback();
409 else
411 if( !isFullScreen() && !isMaximized() && !b_isWindowTiled )
412 resizeWindow( width(), height() + resumePanel->height() );
413 resumePanel->setVisible(true);
414 resumeTimer->start();
418 void MainInterface::hideResumePanel()
420 if( resumePanel->isVisible() )
422 if( !isFullScreen() && !isMaximized() && !b_isWindowTiled )
423 resizeWindow( width(), height() - resumePanel->height() );
424 resumePanel->hide();
425 resumeTimer->stop();
429 void MainInterface::resumePlayback()
431 if( THEMIM->getIM()->hasInput() ) {
432 var_SetInteger( THEMIM->getInput(), "time", i_resumeTime );
434 hideResumePanel();
437 void MainInterface::onInputChanged( bool hasInput )
439 if( hasInput == false )
440 return;
441 int autoRaise = var_InheritInteger( p_intf, "qt-auto-raise" );
442 if ( autoRaise == MainInterface::RAISE_NEVER )
443 return;
444 if( THEMIM->getIM()->hasVideo() == true )
446 if( ( autoRaise & MainInterface::RAISE_VIDEO ) == 0 )
447 return;
449 else if ( ( autoRaise & MainInterface::RAISE_AUDIO ) == 0 )
450 return;
451 emit askRaise();
454 void MainInterface::createMainWidget( QSettings *creationSettings )
456 /* Create the main Widget and the mainLayout */
457 QWidget *main = new QWidget;
458 setCentralWidget( main );
459 mainLayout = new QVBoxLayout( main );
460 main->setContentsMargins( 0, 0, 0, 0 );
461 mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
463 createResumePanel( main );
464 /* */
465 stackCentralW = new QVLCStackedWidget( main );
467 /* Bg Cone */
468 if ( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY
469 && var_InheritBool( p_intf, "qt-icon-change" ) )
471 bgWidget = new EasterEggBackgroundWidget( p_intf );
472 CONNECT( this, kc_pressed(), bgWidget, animate() );
474 else
475 bgWidget = new BackgroundWidget( p_intf );
477 stackCentralW->addWidget( bgWidget );
478 if ( !var_InheritBool( p_intf, "qt-bgcone" ) )
479 bgWidget->setWithArt( false );
480 else
481 if ( var_InheritBool( p_intf, "qt-bgcone-expands" ) )
482 bgWidget->setExpandstoHeight( true );
484 /* And video Outputs */
485 if( var_InheritBool( p_intf, "embedded-video" ) )
487 videoWidget = new VideoWidget( p_intf, stackCentralW );
488 stackCentralW->addWidget( videoWidget );
490 mainLayout->insertWidget( 1, stackCentralW );
492 stackWidgetsSizes[bgWidget] =
493 creationSettings->value( "MainWindow/bgSize", QSize( 600, 0 ) ).toSize();
494 /* Resize even if no-auto-resize, because we are at creation */
495 resizeStack( stackWidgetsSizes[bgWidget].width(), stackWidgetsSizes[bgWidget].height() );
497 /* Create the CONTROLS Widget */
498 controls = new ControlsWidget( p_intf,
499 creationSettings->value( "MainWindow/adv-controls", false ).toBool(), this );
500 inputC = new InputControlsWidget( p_intf, this );
502 mainLayout->insertWidget( 2, inputC );
503 mainLayout->insertWidget(
504 creationSettings->value( "MainWindow/ToolbarPos", false ).toBool() ? 0: 3,
505 controls );
507 /* Visualisation, disabled for now, they SUCK */
508 #if 0
509 visualSelector = new VisualSelector( p_intf );
510 mainLayout->insertWidget( 0, visualSelector );
511 visualSelector->hide();
512 #endif
515 /* Enable the popup menu in the MI */
516 main->setContextMenuPolicy( Qt::CustomContextMenu );
517 CONNECT( main, customContextMenuRequested( const QPoint& ),
518 THEDP, setPopupMenu() );
520 if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
521 /* Create the FULLSCREEN CONTROLS Widget */
522 if( var_InheritBool( p_intf, "qt-fs-controller" ) )
524 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
525 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
526 this, handleKeyPress( QKeyEvent * ) );
529 if ( b_interfaceOnTop )
530 setWindowFlags( windowFlags() | Qt::WindowStaysOnTopHint );
533 inline void MainInterface::initSystray()
535 bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
536 bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
538 if( var_InheritBool( p_intf, "qt-start-minimized") )
540 if( b_systrayAvailable )
542 b_systrayWanted = true;
543 b_hideAfterCreation = true;
545 else
546 msg_Err( p_intf, "cannot start minimized without system tray bar" );
549 if( b_systrayAvailable && b_systrayWanted )
550 createSystray();
553 inline void MainInterface::createStatusBar()
555 /****************
556 * Status Bar *
557 ****************/
558 /* Widgets Creation*/
559 QStatusBar *statusBarr = statusBar();
561 TimeLabel *timeLabel = new TimeLabel( p_intf );
562 nameLabel = new ClickableQLabel();
563 nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
564 | Qt::TextSelectableByKeyboard );
565 SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
567 /* Styling those labels */
568 timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
569 speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
570 nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
571 timeLabel->setStyleSheet(
572 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
573 speedLabel->setStyleSheet(
574 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
575 /* pad both label and its tooltip */
576 nameLabel->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
578 /* and adding those */
579 statusBarr->addWidget( nameLabel, 8 );
580 statusBarr->addPermanentWidget( speedLabel, 0 );
581 statusBarr->addPermanentWidget( timeLabel, 0 );
583 CONNECT( nameLabel, doubleClicked(), THEDP, epgDialog() );
584 /* timeLabel behaviour:
585 - double clicking opens the goto time dialog
586 - right-clicking and clicking just toggle between remaining and
587 elapsed time.*/
588 CONNECT( timeLabel, doubleClicked(), THEDP, gotoTimeDialog() );
590 CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
591 this, showCryptedLabel( bool ) );
593 CONNECT( THEMIM->getIM(), seekRequested( float ),
594 timeLabel, setDisplayPosition( float ) );
596 /* This shouldn't be necessary, but for somehow reason, the statusBarr
597 starts at height of 20px and when a text is shown it needs more space.
598 But, as the QMainWindow policy doesn't allow statusBar to change QMW's
599 geometry, we need to force a height. If you have a better idea, please
600 tell me -- jb
602 statusBarr->setFixedHeight( statusBarr->sizeHint().height() + 2 );
605 /**********************************************************************
606 * Handling of sizing of the components
607 **********************************************************************/
609 void MainInterface::debug()
611 #ifdef DEBUG_INTF
612 if( controls ) {
613 msg_Dbg( p_intf, "Controls size: %i - %i", controls->size().height(), controls->size().width() );
614 msg_Dbg( p_intf, "Controls minimumsize: %i - %i", controls->minimumSize().height(), controls->minimumSize().width() );
615 msg_Dbg( p_intf, "Controls sizeHint: %i - %i", controls->sizeHint().height(), controls->sizeHint().width() );
618 msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
619 msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
620 msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
622 msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
623 msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
624 msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
625 #endif
628 inline void MainInterface::showVideo() { showTab( videoWidget ); }
629 inline void MainInterface::restoreStackOldWidget()
630 { showTab( stackCentralOldWidget ); }
632 inline void MainInterface::showTab( QWidget *widget )
634 if ( !widget ) widget = bgWidget; /* trying to restore a null oldwidget */
635 #ifdef DEBUG_INTF
636 if ( stackCentralOldWidget )
637 msg_Dbg( p_intf, "Old stackCentralOldWidget %s at index %i",
638 stackCentralOldWidget->metaObject()->className(),
639 stackCentralW->indexOf( stackCentralOldWidget ) );
640 msg_Dbg( p_intf, "ShowTab request for %s", widget->metaObject()->className() );
641 #endif
642 if ( stackCentralW->currentWidget() == widget )
643 return;
645 /* fixing when the playlist has been undocked after being hidden.
646 restoreStackOldWidget() is called when video stops but
647 stackCentralOldWidget would still be pointing to playlist */
648 if ( widget == playlistWidget && !isPlDocked() )
649 widget = bgWidget;
651 stackCentralOldWidget = stackCentralW->currentWidget();
652 stackWidgetsSizes[stackCentralOldWidget] = stackCentralW->size();
654 /* If we are playing video, embedded */
655 if( videoWidget && THEMIM->getIM()->hasVideo() )
657 /* Video -> Playlist */
658 if( videoWidget == stackCentralOldWidget && widget == playlistWidget )
660 stackCentralW->removeWidget( videoWidget );
661 videoWidget->show(); videoWidget->raise();
664 /* Playlist -> Video */
665 if( playlistWidget == stackCentralOldWidget && widget == videoWidget )
667 playlistWidget->artContainer->removeWidget( videoWidget );
668 videoWidget->show(); videoWidget->raise();
669 stackCentralW->addWidget( videoWidget );
672 /* Embedded playlist -> Non-embedded playlist */
673 if( bgWidget == stackCentralOldWidget && widget == videoWidget )
675 /* In rare case when video is started before the interface */
676 if( playlistWidget != NULL )
677 playlistWidget->artContainer->removeWidget( videoWidget );
678 videoWidget->show(); videoWidget->raise();
679 stackCentralW->addWidget( videoWidget );
680 stackCentralW->setCurrentWidget( videoWidget );
684 stackCentralW->setCurrentWidget( widget );
685 if( b_autoresize )
686 resizeStack( stackWidgetsSizes[widget].width(), stackWidgetsSizes[widget].height() );
688 #ifdef DEBUG_INTF
689 msg_Dbg( p_intf, "Stack state changed to %s, index %i",
690 stackCentralW->currentWidget()->metaObject()->className(),
691 stackCentralW->currentIndex() );
692 msg_Dbg( p_intf, "New stackCentralOldWidget %s at index %i",
693 stackCentralOldWidget->metaObject()->className(),
694 stackCentralW->indexOf( stackCentralOldWidget ) );
695 #endif
697 /* This part is done later, to account for the new pl size */
698 if( videoWidget && THEMIM->getIM()->hasVideo() &&
699 videoWidget == stackCentralOldWidget && widget == playlistWidget )
701 playlistWidget->artContainer->addWidget( videoWidget );
702 playlistWidget->artContainer->setCurrentWidget( videoWidget );
706 void MainInterface::toggleFSC()
708 if( !fullscreenControls ) return;
710 IMEvent *eShow = new IMEvent( IMEvent::FullscreenControlToggle );
711 QApplication::postEvent( fullscreenControls, eShow );
714 /****************************************************************************
715 * Video Handling
716 ****************************************************************************/
719 * NOTE:
720 * You must not change the state of this object or other Qt UI objects,
721 * from the video output thread - only from the Qt UI main loop thread.
722 * All window provider queries must be handled through signals or events.
723 * That's why we have all those emit statements...
725 bool MainInterface::getVideo( struct vout_window_t *p_wnd,
726 unsigned int i_width, unsigned int i_height,
727 bool fullscreen )
729 bool result;
731 /* This is a blocking call signal. Results are stored directly in the
732 * vout_window_t and boolean pointers. Beware of deadlocks! */
733 emit askGetVideo( p_wnd, i_width, i_height, fullscreen, &result );
734 return result;
737 void MainInterface::getVideoSlot( struct vout_window_t *p_wnd,
738 unsigned i_width, unsigned i_height,
739 bool fullscreen, bool *res )
741 /* Hidden or minimized, activate */
742 if( isHidden() || isMinimized() )
743 toggleUpdateSystrayMenu();
745 /* Request the videoWidget */
746 if ( !videoWidget )
748 videoWidget = new VideoWidget( p_intf, stackCentralW );
749 stackCentralW->addWidget( videoWidget );
751 *res = videoWidget->request( p_wnd );
752 if( *res ) /* The videoWidget is available */
754 setVideoFullScreen( fullscreen );
756 /* Consider the video active now */
757 showVideo();
759 /* Ask videoWidget to resize correctly, if we are in normal mode */
760 if( b_autoresize ) {
761 #if HAS_QT56
762 qreal factor = videoWidget->devicePixelRatioF();
764 i_width = qRound( (qreal) i_width / factor );
765 i_height = qRound( (qreal) i_height / factor );
766 #endif
768 videoWidget->setSize( i_width, i_height );
773 /* Asynchronous call from the WindowClose function */
774 void MainInterface::releaseVideo( void )
776 emit askReleaseVideo();
779 /* Function that is CONNECTED to the previous emit */
780 void MainInterface::releaseVideoSlot( void )
782 /* This function is called when the embedded video window is destroyed,
783 * or in the rare case that the embedded window is still here but the
784 * Qt interface exits. */
785 assert( videoWidget );
786 videoWidget->release();
787 setVideoOnTop( false );
788 setVideoFullScreen( false );
789 hideResumePanel();
791 if( stackCentralW->currentWidget() == videoWidget )
792 restoreStackOldWidget();
793 else if( playlistWidget &&
794 playlistWidget->artContainer->currentWidget() == videoWidget )
796 playlistWidget->artContainer->setCurrentIndex( 0 );
797 stackCentralW->addWidget( videoWidget );
800 /* We don't want to have a blank video to popup */
801 stackCentralOldWidget = bgWidget;
804 // The provided size is in physical pixels, coming from the core.
805 void MainInterface::setVideoSize( unsigned int w, unsigned int h )
807 if (!isFullScreen() && !isMaximized() )
809 /* Resize video widget to video size, or keep it at the same
810 * size. Call setSize() either way so that vout_window_ReportSize
811 * will always get called.
812 * If the video size is too large for the screen, resize it
813 * to the screen size.
815 if (b_autoresize)
817 QRect screen = QApplication::desktop()->availableGeometry();
818 #if HAS_QT56
819 float factor = videoWidget->devicePixelRatioF();
820 #else
821 float factor = 1.0f;
822 #endif
823 if( (float)h / factor > screen.height() )
825 w = screen.width();
826 h = screen.height();
827 if( !b_minimalView )
829 if( menuBar()->isVisible() )
830 h -= menuBar()->height();
831 if( controls->isVisible() )
832 h -= controls->height();
833 if( statusBar()->isVisible() )
834 h -= statusBar()->height();
835 if( inputC->isVisible() )
836 h -= inputC->height();
838 h -= style()->pixelMetric(QStyle::PM_TitleBarHeight);
839 h -= style()->pixelMetric(QStyle::PM_LayoutBottomMargin);
840 h -= 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
842 else
844 // Convert the size in logical pixels
845 w = qRound( (float)w / factor );
846 h = qRound( (float)h / factor );
847 msg_Dbg( p_intf, "Logical video size: %ux%u", w, h );
849 videoWidget->setSize( w, h );
851 else
852 videoWidget->setSize( videoWidget->width(), videoWidget->height() );
856 void MainInterface::videoSizeChanged( int w, int h )
858 if( !playlistWidget || playlistWidget->artContainer->currentWidget() != videoWidget )
859 resizeStack( w, h );
862 void MainInterface::setVideoFullScreen( bool fs )
864 b_videoFullScreen = fs;
865 if( fs )
867 int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
868 /* if user hasn't defined screennumber, or screennumber that is bigger
869 * than current number of screens, take screennumber where current interface
870 * is
872 if( numscreen < 0 || numscreen >= QApplication::desktop()->screenCount() )
873 numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
875 if( fullscreenControls )
876 fullscreenControls->setTargetScreen( numscreen );
878 if ( numscreen >= 0 )
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() ) );
899 /* */
900 if( playlistWidget != NULL && playlistWidget->artContainer->currentWidget() == videoWidget )
902 showTab( videoWidget );
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 resizeWindow( lastWinSize.width(), lastWinSize.height() );
925 lastWinPosition = QPoint();
926 lastWinSize = QSize();
930 videoWidget->sync();
933 void MainInterface::setHideMouse( bool hide )
935 videoWidget->setCursor( hide ? Qt::BlankCursor : Qt::ArrowCursor );
938 /* Slot to change the video always-on-top flag.
939 * Emit askVideoOnTop() to invoke this from other thread. */
940 void MainInterface::setVideoOnTop( bool on_top )
942 //don't apply changes if user has already sets its interface on top
943 if ( b_interfaceOnTop )
944 return;
946 Qt::WindowFlags oldflags = windowFlags(), newflags;
948 if( on_top )
949 newflags = oldflags | Qt::WindowStaysOnTopHint;
950 else
951 newflags = oldflags & ~Qt::WindowStaysOnTopHint;
952 if( newflags != oldflags && !b_videoFullScreen )
954 setWindowFlags( newflags );
955 show(); /* necessary to apply window flags */
959 void MainInterface::setInterfaceAlwaysOnTop( bool on_top )
961 b_interfaceOnTop = on_top;
962 Qt::WindowFlags oldflags = windowFlags(), newflags;
964 if( on_top )
965 newflags = oldflags | Qt::WindowStaysOnTopHint;
966 else
967 newflags = oldflags & ~Qt::WindowStaysOnTopHint;
968 if( newflags != oldflags && !b_videoFullScreen )
970 setWindowFlags( newflags );
971 show(); /* necessary to apply window flags */
975 /* Asynchronous call from WindowControl function */
976 int MainInterface::controlVideo( int i_query, va_list args )
978 switch( i_query )
980 case VOUT_WINDOW_SET_SIZE:
982 unsigned int i_width = va_arg( args, unsigned int );
983 unsigned int i_height = va_arg( args, unsigned int );
985 emit askVideoToResize( i_width, i_height );
986 return VLC_SUCCESS;
988 case VOUT_WINDOW_SET_STATE:
990 unsigned i_arg = va_arg( args, unsigned );
991 unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
993 emit askVideoOnTop( on_top != 0 );
994 return VLC_SUCCESS;
996 case VOUT_WINDOW_SET_FULLSCREEN:
998 bool b_fs = va_arg( args, int );
1000 emit askVideoSetFullScreen( b_fs );
1001 return VLC_SUCCESS;
1003 case VOUT_WINDOW_HIDE_MOUSE:
1005 bool b_hide = va_arg( args, int );
1007 emit askHideMouse( b_hide );
1008 return VLC_SUCCESS;
1010 default:
1011 msg_Warn( p_intf, "unsupported control query" );
1012 return VLC_EGENERIC;
1016 /*****************************************************************************
1017 * Playlist, Visualisation and Menus handling
1018 *****************************************************************************/
1020 * Toggle the playlist widget or dialog
1022 void MainInterface::createPlaylist()
1024 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
1026 if( b_plDocked )
1028 playlistWidget = dialog->exportPlaylistWidget();
1029 stackCentralW->addWidget( playlistWidget );
1030 stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 600, 300 ) ).toSize();
1032 CONNECT( dialog, visibilityChanged(bool), this, setPlaylistVisibility(bool) );
1035 void MainInterface::togglePlaylist()
1037 if( !playlistWidget ) createPlaylist();
1039 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
1040 if( b_plDocked )
1042 if ( dialog->hasPlaylistWidget() )
1043 playlistWidget = dialog->exportPlaylistWidget();
1044 /* Playlist is not visible, show it */
1045 if( stackCentralW->currentWidget() != playlistWidget )
1047 if( stackCentralW->indexOf( playlistWidget ) == -1 )
1048 stackCentralW->addWidget( playlistWidget );
1049 showTab( playlistWidget );
1051 else /* Hide it! */
1053 restoreStackOldWidget();
1055 playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
1057 else
1059 playlistVisible = !playlistVisible;
1060 if ( ! dialog->hasPlaylistWidget() )
1061 dialog->importPlaylistWidget( playlistWidget );
1062 if ( playlistVisible )
1063 dialog->show();
1064 else
1065 dialog->hide();
1067 debug();
1070 const Qt::Key MainInterface::kc[10] =
1072 Qt::Key_Up, Qt::Key_Up,
1073 Qt::Key_Down, Qt::Key_Down,
1074 Qt::Key_Left, Qt::Key_Right, Qt::Key_Left, Qt::Key_Right,
1075 Qt::Key_B, Qt::Key_A
1078 void MainInterface::dockPlaylist( bool p_docked )
1080 if( b_plDocked == p_docked ) return;
1081 /* some extra check */
1082 if ( b_plDocked && !playlistWidget ) createPlaylist();
1084 b_plDocked = p_docked;
1085 PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
1087 if( !p_docked ) /* Previously docked */
1089 playlistVisible = playlistWidget->isVisible();
1091 /* repositioning the videowidget __before__ exporting the
1092 playlistwidget into the playlist dialog avoids two unneeded
1093 calls to the server in the qt library to reparent the underlying
1094 native window back and forth.
1095 For Wayland, this is mandatory since reparenting is not implemented.
1096 For X11 or Windows, this is just an optimization. */
1097 if ( videoWidget && THEMIM->getIM()->hasVideo() )
1098 showTab(videoWidget);
1099 else
1100 showTab(bgWidget);
1102 /* playlistwidget exported into the playlist dialog */
1103 stackCentralW->removeWidget( playlistWidget );
1104 dialog->importPlaylistWidget( playlistWidget );
1105 if ( playlistVisible ) dialog->show();
1107 else /* Previously undocked */
1109 playlistVisible = dialog->isVisible() && !( videoWidget && THEMIM->getIM()->hasVideo() );
1110 dialog->hide();
1111 playlistWidget = dialog->exportPlaylistWidget();
1112 stackCentralW->addWidget( playlistWidget );
1114 /* If playlist is invisible don't show it */
1115 if( playlistVisible ) showTab( playlistWidget );
1120 * displayNormalView is the private function used by
1121 * the SLOT setVideoFullScreen to restore the menuBar
1122 * if minimal view is off
1124 void MainInterface::displayNormalView()
1126 menuBar()->setVisible( false );
1127 controls->setVisible( false );
1128 statusBar()->setVisible( false );
1129 inputC->setVisible( false );
1133 * setMinimalView is the private function used by
1134 * the SLOT toggleMinimalView
1136 void MainInterface::setMinimalView( bool b_minimal )
1138 bool b_menuBarVisible = menuBar()->isVisible();
1139 bool b_controlsVisible = controls->isVisible();
1140 bool b_statusBarVisible = statusBar()->isVisible();
1141 bool b_inputCVisible = inputC->isVisible();
1143 if( !isFullScreen() && !isMaximized() && b_minimal && !b_isWindowTiled )
1145 int i_heightChange = 0;
1147 if( b_menuBarVisible )
1148 i_heightChange += menuBar()->height();
1149 if( b_controlsVisible )
1150 i_heightChange += controls->height();
1151 if( b_statusBarVisible )
1152 i_heightChange += statusBar()->height();
1153 if( b_inputCVisible )
1154 i_heightChange += inputC->height();
1156 if( i_heightChange != 0 )
1157 resizeWindow( width(), height() - i_heightChange );
1160 menuBar()->setVisible( !b_minimal );
1161 controls->setVisible( !b_minimal );
1162 statusBar()->setVisible( !b_minimal && b_statusbarVisible );
1163 inputC->setVisible( !b_minimal );
1165 if( !isFullScreen() && !isMaximized() && !b_minimal && !b_isWindowTiled )
1167 int i_heightChange = 0;
1169 if( !b_menuBarVisible && menuBar()->isVisible() )
1170 i_heightChange += menuBar()->height();
1171 if( !b_controlsVisible && controls->isVisible() )
1172 i_heightChange += controls->height();
1173 if( !b_statusBarVisible && statusBar()->isVisible() )
1174 i_heightChange += statusBar()->height();
1175 if( !b_inputCVisible && inputC->isVisible() )
1176 i_heightChange += inputC->height();
1178 if( i_heightChange != 0 )
1179 resizeWindow( width(), height() + i_heightChange );
1184 * This public SLOT is used for moving to minimal View Mode
1186 * If b_minimal is false, then we are normalView
1188 void MainInterface::toggleMinimalView( bool b_minimal )
1190 if( !b_minimalView && b_autoresize ) /* Normal mode */
1192 if( stackCentralW->currentWidget() == bgWidget )
1194 if( stackCentralW->height() < 16 )
1196 resizeStack( stackCentralW->width(), 100 );
1200 b_minimalView = b_minimal;
1201 if( !b_videoFullScreen )
1203 setMinimalView( b_minimalView );
1204 computeMinimumSize();
1207 emit minimalViewToggled( b_minimalView );
1210 /* toggling advanced controls buttons */
1211 void MainInterface::toggleAdvancedButtons()
1213 controls->toggleAdvanced();
1214 // if( fullscreenControls ) fullscreenControls->toggleAdvanced();
1217 /* Get the visibility status of the controls (hidden or not, advanced or not) */
1218 int MainInterface::getControlsVisibilityStatus()
1220 if( !controls ) return 0;
1221 return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
1222 + CONTROLS_ADVANCED * controls->b_advancedVisible );
1225 StandardPLPanel *MainInterface::getPlaylistView()
1227 if( !playlistWidget ) return NULL;
1228 else return playlistWidget->mainView;
1231 void MainInterface::setStatusBarVisibility( bool b_visible )
1233 statusBar()->setVisible( b_visible );
1234 b_statusbarVisible = b_visible;
1235 if( controls ) controls->setGripVisible( !b_statusbarVisible );
1239 void MainInterface::setPlaylistVisibility( bool b_visible )
1241 if( isPlDocked() || THEDP->isDying() || (playlistWidget && playlistWidget->isMinimized() ) )
1242 return;
1244 playlistVisible = b_visible;
1247 /************************************************************************
1248 * Other stuff
1249 ************************************************************************/
1250 void MainInterface::setName( const QString& name )
1252 input_name = name; /* store it for the QSystray use */
1253 /* Display it in the status bar, but also as a Tooltip in case it doesn't
1254 fit in the label */
1255 nameLabel->setText( name );
1256 nameLabel->setToolTip( name );
1260 * Give the decorations of the Main Window a correct Name.
1261 * If nothing is given, set it to VLC...
1263 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
1265 if( aTitle.isEmpty() )
1267 setWindowTitle( qtr( "VLC media player" ) );
1269 else
1271 setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
1275 void MainInterface::showCryptedLabel( bool b_show )
1277 if( cryptedLabel == NULL )
1279 cryptedLabel = new QLabel;
1280 // The lock icon is not the right one for DRM protection/scrambled.
1281 //cryptedLabel->setPixmap( QPixmap( ":/lock.svg" ) );
1282 cryptedLabel->setText( "DRM" );
1283 statusBar()->addWidget( cryptedLabel );
1286 cryptedLabel->setVisible( b_show );
1289 void MainInterface::showBuffering( float f_cache )
1291 QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
1292 statusBar()->showMessage( amount, 1000 );
1295 /*****************************************************************************
1296 * Systray Icon and Systray Menu
1297 *****************************************************************************/
1299 * Create a SystemTray icon and a menu that would go with it.
1300 * Connects to a click handler on the icon.
1302 void MainInterface::createSystray()
1304 QIcon iconVLC;
1305 if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
1306 iconVLC = QIcon::fromTheme( "vlc-xmas", QIcon( ":/logo/vlc128-xmas.png" ) );
1307 else
1308 iconVLC = QIcon::fromTheme( "vlc", QIcon( ":/logo/vlc256.png" ) );
1309 sysTray = new QSystemTrayIcon( iconVLC, this );
1310 sysTray->setToolTip( qtr( "VLC media player" ));
1312 systrayMenu = new QMenu( qtr( "VLC media player" ), this );
1313 systrayMenu->setIcon( iconVLC );
1315 VLCMenuBar::updateSystrayMenu( this, p_intf, true );
1316 sysTray->show();
1318 CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
1319 this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
1321 /* Connects on nameChanged() */
1322 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
1323 this, updateSystrayTooltipName( const QString& ) );
1324 /* Connect PLAY_STATUS on the systray */
1325 CONNECT( THEMIM->getIM(), playingStatusChanged( int ),
1326 this, updateSystrayTooltipStatus( int ) );
1329 void MainInterface::toggleUpdateSystrayMenuWhenVisible()
1331 hide();
1334 void MainInterface::resizeWindow(int w, int h)
1336 #if ! HAS_QT510 && defined(QT5_HAS_X11)
1337 if( QX11Info::isPlatformX11() )
1339 #if HAS_QT56
1340 qreal dpr = devicePixelRatioF();
1341 #else
1342 qreal dpr = devicePixelRatio();
1343 #endif
1344 QSize size(w, h);
1345 size = size.boundedTo(maximumSize()).expandedTo(minimumSize());
1346 /* X11 window managers are not required to accept geometry changes on
1347 * the top-level window. Unfortunately, Qt < 5.10 assumes that the
1348 * change will succeed, and resizes all sub-windows unconditionally.
1349 * By calling XMoveResizeWindow directly, Qt will not see our change
1350 * request until the ConfigureNotify event on success
1351 * and not at all if it is rejected. */
1352 XMoveResizeWindow( QX11Info::display(), winId(),
1353 geometry().x() * dpr, geometry().y() * dpr,
1354 (unsigned int)size.width() * dpr, (unsigned int)size.height() * dpr);
1355 return;
1357 #endif
1358 resize(w, h);
1362 * Updates the Systray Icon's menu and toggle the main interface
1364 void MainInterface::toggleUpdateSystrayMenu()
1366 /* If hidden, show it */
1367 if( isHidden() )
1369 show();
1370 activateWindow();
1372 else if( isMinimized() )
1374 /* Minimized */
1375 showNormal();
1376 activateWindow();
1378 else
1380 /* Visible (possibly under other windows) */
1381 toggleUpdateSystrayMenuWhenVisible();
1383 if( sysTray )
1384 VLCMenuBar::updateSystrayMenu( this, p_intf );
1387 /* First Item of the systray menu */
1388 void MainInterface::showUpdateSystrayMenu()
1390 if( isHidden() )
1391 show();
1392 if( isMinimized() )
1393 showNormal();
1394 activateWindow();
1396 VLCMenuBar::updateSystrayMenu( this, p_intf );
1399 /* First Item of the systray menu */
1400 void MainInterface::hideUpdateSystrayMenu()
1402 hide();
1403 VLCMenuBar::updateSystrayMenu( this, p_intf );
1406 /* Click on systray Icon */
1407 void MainInterface::handleSystrayClick(
1408 QSystemTrayIcon::ActivationReason reason )
1410 switch( reason )
1412 case QSystemTrayIcon::Trigger:
1413 case QSystemTrayIcon::DoubleClick:
1414 #ifdef Q_OS_MAC
1415 VLCMenuBar::updateSystrayMenu( this, p_intf );
1416 #else
1417 toggleUpdateSystrayMenu();
1418 #endif
1419 break;
1420 case QSystemTrayIcon::MiddleClick:
1421 sysTray->showMessage( qtr( "VLC media player" ),
1422 qtr( "Control menu for the player" ),
1423 QSystemTrayIcon::Information, 3000 );
1424 break;
1425 default:
1426 break;
1431 * Updates the name of the systray Icon tooltip.
1432 * Doesn't check if the systray exists, check before you call it.
1434 void MainInterface::updateSystrayTooltipName( const QString& name )
1436 if( name.isEmpty() )
1438 sysTray->setToolTip( qtr( "VLC media player" ) );
1440 else
1442 sysTray->setToolTip( name );
1443 if( ( i_notificationSetting == NOTIFICATION_ALWAYS ) ||
1444 ( i_notificationSetting == NOTIFICATION_MINIMIZED && (isMinimized() || isHidden()) ) )
1446 sysTray->showMessage( qtr( "VLC media player" ), name,
1447 QSystemTrayIcon::NoIcon, 3000 );
1451 VLCMenuBar::updateSystrayMenu( this, p_intf );
1455 * Updates the status of the systray Icon tooltip.
1456 * Doesn't check if the systray exists, check before you call it.
1458 void MainInterface::updateSystrayTooltipStatus( int i_status )
1460 switch( i_status )
1462 case PLAYING_S:
1463 sysTray->setToolTip( input_name );
1464 break;
1465 case PAUSE_S:
1466 sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1467 break;
1468 default:
1469 sysTray->setToolTip( qtr( "VLC media player" ) );
1470 break;
1472 VLCMenuBar::updateSystrayMenu( this, p_intf );
1475 void MainInterface::changeEvent(QEvent *event)
1477 if( event->type() == QEvent::WindowStateChange )
1479 QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
1480 Qt::WindowStates newState = windowState();
1481 Qt::WindowStates oldState = windowStateChangeEvent->oldState();
1483 /* b_maximizedView stores if the window was maximized before entering fullscreen.
1484 * It is set when entering maximized mode, unset when leaving it to normal mode.
1485 * Upon leaving full screen, if b_maximizedView is set,
1486 * the window should be maximized again. */
1487 if( newState & Qt::WindowMaximized &&
1488 !( oldState & Qt::WindowMaximized ) )
1489 b_maximizedView = true;
1491 if( !( newState & Qt::WindowMaximized ) &&
1492 oldState & Qt::WindowMaximized &&
1493 !b_videoFullScreen )
1494 b_maximizedView = false;
1496 if( !( newState & Qt::WindowFullScreen ) &&
1497 oldState & Qt::WindowFullScreen &&
1498 b_maximizedView )
1500 showMaximized();
1501 return;
1504 if( newState & Qt::WindowMinimized )
1506 b_hasPausedWhenMinimized = false;
1508 if( THEMIM->getIM()->playingStatus() == PLAYING_S &&
1509 THEMIM->getIM()->hasVideo() && !THEMIM->getIM()->hasVisualisation() &&
1510 b_pauseOnMinimize )
1512 b_hasPausedWhenMinimized = true;
1513 THEMIM->pause();
1516 else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
1518 if( b_hasPausedWhenMinimized )
1520 THEMIM->play();
1525 QWidget::changeEvent(event);
1528 /************************************************************************
1529 * D&D Events
1530 ************************************************************************/
1531 void MainInterface::dropEvent(QDropEvent *event)
1533 dropEventPlay( event, true );
1537 * dropEventPlay
1539 * Event called if something is dropped onto a VLC window
1540 * \param event the event in question
1541 * \param b_play whether to play the file immediately
1542 * \param b_playlist true to add to playlist, false to add to media library
1543 * \return nothing
1545 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play, bool b_playlist )
1547 if( event->possibleActions() & ( Qt::CopyAction | Qt::MoveAction | Qt::LinkAction ) )
1548 event->setDropAction( Qt::CopyAction );
1549 else
1550 return;
1552 const QMimeData *mimeData = event->mimeData();
1554 /* D&D of a subtitles file, add it on the fly */
1555 if( mimeData->urls().count() == 1 && THEMIM->getIM()->hasInput() )
1557 if( !input_AddSlave( THEMIM->getInput(), SLAVE_TYPE_SPU,
1558 qtu( mimeData->urls()[0].toString() ), true, true, true ) )
1560 event->accept();
1561 return;
1565 bool first = b_play;
1566 foreach( const QUrl &url, mimeData->urls() )
1568 if( url.isValid() )
1570 QString mrl = toURI( url.toEncoded().constData() );
1571 #ifdef _WIN32
1572 QFileInfo info( url.toLocalFile() );
1573 if( info.exists() && info.isSymLink() )
1575 QString target = info.symLinkTarget();
1576 QUrl url;
1577 if( QFile::exists( target ) )
1579 url = QUrl::fromLocalFile( target );
1581 else
1583 url.setUrl( target );
1585 mrl = toURI( url.toEncoded().constData() );
1587 #endif
1588 if( mrl.length() > 0 )
1590 Open::openMRL( p_intf, mrl, first, b_playlist );
1591 first = false;
1596 /* Browsers give content as text if you dnd the addressbar,
1597 so check if mimedata has valid url in text and use it
1598 if we didn't get any normal Urls()*/
1599 if( !mimeData->hasUrls() && mimeData->hasText() &&
1600 QUrl(mimeData->text()).isValid() )
1602 QString mrl = toURI( mimeData->text() );
1603 Open::openMRL( p_intf, mrl, first, b_playlist );
1605 event->accept();
1607 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1609 event->acceptProposedAction();
1611 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1613 event->acceptProposedAction();
1615 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1617 event->accept();
1620 /************************************************************************
1621 * Events stuff
1622 ************************************************************************/
1623 void MainInterface::keyPressEvent( QKeyEvent *e )
1625 handleKeyPress( e );
1627 /* easter eggs sequence handling */
1628 if ( e->key() == kc[ i_kc_offset ] )
1629 i_kc_offset++;
1630 else
1631 i_kc_offset = 0;
1633 if ( i_kc_offset == (sizeof( kc ) / sizeof( Qt::Key )) )
1635 i_kc_offset = 0;
1636 emit kc_pressed();
1640 void MainInterface::handleKeyPress( QKeyEvent *e )
1642 if( ( ( e->modifiers() & Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) ) ||
1643 ( b_minimalView && !b_videoFullScreen && e->key() == Qt::Key_Escape ) )
1645 toggleMinimalView( !b_minimalView );
1646 e->accept();
1648 else if( ( e->modifiers() & Qt::ControlModifier ) && ( e->key() == Qt::Key_K ) &&
1649 playlistWidget )
1651 playlistWidget->setSearchFieldFocus();
1652 e->accept();
1655 int i_vlck = qtEventToVLCKey( e );
1656 if( i_vlck > 0 )
1658 var_SetInteger( p_intf->obj.libvlc, "key-pressed", i_vlck );
1659 e->accept();
1661 else
1662 e->ignore();
1665 void MainInterface::wheelEvent( QWheelEvent *e )
1667 int i_vlckey = qtWheelEventToVLCKey( e );
1668 var_SetInteger( p_intf->obj.libvlc, "key-pressed", i_vlckey );
1669 e->accept();
1672 void MainInterface::closeEvent( QCloseEvent *e )
1674 // hide();
1675 if ( b_minimalView )
1676 setMinimalView( false );
1677 emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
1678 /* Accept session quit. Otherwise we break the desktop mamager. */
1679 e->accept();
1682 bool MainInterface::eventFilter( QObject *obj, QEvent *event )
1684 if ( event->type() == MainInterface::ToolbarsNeedRebuild ) {
1685 event->accept();
1686 recreateToolbars();
1687 return true;
1688 } else {
1689 return QObject::eventFilter( obj, event );
1693 void MainInterface::toolBarConfUpdated()
1695 QApplication::postEvent( this, new QEvent( MainInterface::ToolbarsNeedRebuild ) );
1698 void MainInterface::setInterfaceFullScreen( bool fs )
1700 if( fs )
1701 setWindowState( windowState() | Qt::WindowFullScreen );
1702 else
1703 setWindowState( windowState() & ~Qt::WindowFullScreen );
1705 void MainInterface::toggleInterfaceFullScreen()
1707 b_interfaceFullScreen = !b_interfaceFullScreen;
1708 if( !b_videoFullScreen )
1709 setInterfaceFullScreen( b_interfaceFullScreen );
1710 emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1713 void MainInterface::emitBoss()
1715 emit askBoss();
1717 void MainInterface::setBoss()
1719 THEMIM->pause();
1720 if( sysTray )
1722 hide();
1724 else
1726 showMinimized();
1730 void MainInterface::emitRaise()
1732 emit askRaise();
1734 void MainInterface::setRaise()
1736 activateWindow();
1737 raise();
1740 void MainInterface::voutReleaseMouseEvents()
1742 if (videoWidget)
1744 QPoint pos = QCursor::pos();
1745 QPoint localpos = videoWidget->mapFromGlobal(pos);
1746 int buttons = QApplication::mouseButtons();
1747 int i_button = 1;
1748 while (buttons != 0)
1750 if ( (buttons & 1) != 0 )
1752 QMouseEvent new_e( QEvent::MouseButtonRelease, localpos,
1753 (Qt::MouseButton)i_button, (Qt::MouseButton)i_button, Qt::NoModifier );
1754 QApplication::sendEvent(videoWidget, &new_e);
1756 buttons >>= 1;
1757 i_button <<= 1;
1763 /*****************************************************************************
1764 * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1765 * We don't show the menu directly here because we don't want the
1766 * caller to block for a too long time.
1767 *****************************************************************************/
1768 static int PopupMenuCB( vlc_object_t *, const char *,
1769 vlc_value_t, vlc_value_t new_val, void *param )
1771 intf_thread_t *p_intf = (intf_thread_t *)param;
1773 if( p_intf->pf_show_dialog )
1775 p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1776 new_val.b_bool, NULL );
1779 return VLC_SUCCESS;
1782 /*****************************************************************************
1783 * IntfShowCB: callback triggered by the intf-toggle-fscontrol libvlc variable.
1784 *****************************************************************************/
1785 static int IntfShowCB( vlc_object_t *, const char *,
1786 vlc_value_t, vlc_value_t, void *param )
1788 intf_thread_t *p_intf = (intf_thread_t *)param;
1789 p_intf->p_sys->p_mi->toggleFSC();
1791 /* Show event */
1792 return VLC_SUCCESS;
1795 /*****************************************************************************
1796 * IntfRaiseMainCB: callback triggered by the intf-show-main libvlc variable.
1797 *****************************************************************************/
1798 static int IntfRaiseMainCB( vlc_object_t *, const char *,
1799 vlc_value_t, vlc_value_t, void *param )
1801 intf_thread_t *p_intf = (intf_thread_t *)param;
1802 p_intf->p_sys->p_mi->emitRaise();
1804 return VLC_SUCCESS;
1807 /*****************************************************************************
1808 * IntfBossCB: callback triggered by the intf-boss libvlc variable.
1809 *****************************************************************************/
1810 static int IntfBossCB( vlc_object_t *, const char *,
1811 vlc_value_t, vlc_value_t, void *param )
1813 intf_thread_t *p_intf = (intf_thread_t *)param;
1814 p_intf->p_sys->p_mi->emitBoss();
1816 return VLC_SUCCESS;