Qt4: Make playlist window drag&drop to current selected PLSelItem
[vlc.git] / modules / gui / qt4 / main_interface.cpp
blob19c65a8b3aeca8a14bdd84ebd8dfa7c1e984d60b
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 "qt4.hpp"
32 #include "main_interface.hpp"
33 #include "input_manager.hpp" // Creation
34 #include "actions_manager.hpp" // killInstance
35 #include "extensions_manager.hpp" // killInstance
37 #include "util/customwidgets.hpp" // qtEventToVLCKey, QVLCStackedWidget
38 #include "util/qt_dirs.hpp" // toNativeSeparators
40 #include "components/interface_widgets.hpp" // bgWidget, videoWidget
41 #include "components/controller.hpp" // controllers
42 #include "components/playlist/playlist.hpp" // plWidget
43 #include "dialogs/firstrun.hpp" // First Run
45 #include "menus.hpp" // Menu creation
46 #include "recents.hpp" // RecentItems when DnD
48 #include <QCloseEvent>
49 #include <QKeyEvent>
51 #include <QUrl>
52 #include <QSize>
53 #include <QDate>
55 #include <QMenu>
56 #include <QMenuBar>
57 #include <QStatusBar>
58 #include <QLabel>
59 #include <QStackedWidget>
61 #include <vlc_keys.h> /* Wheel event */
62 #include <vlc_vout_display.h> /* vout_thread_t and VOUT_ events */
64 // #define DEBUG_INTF
66 /* Callback prototypes */
67 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
68 vlc_value_t old_val, vlc_value_t new_val, void *param );
69 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
70 vlc_value_t old_val, vlc_value_t new_val, void *param );
71 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
72 vlc_value_t old_val, vlc_value_t new_val, void *param );
73 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
74 vlc_value_t old_val, vlc_value_t new_val,
75 void *param );
77 MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
79 /* Variables initialisation */
80 bgWidget = NULL;
81 videoWidget = NULL;
82 playlistWidget = NULL;
83 stackCentralOldWidget= NULL;
84 sysTray = NULL;
85 fullscreenControls = NULL;
86 cryptedLabel = NULL;
87 controls = NULL;
88 inputC = NULL;
90 b_hideAfterCreation = false; // --qt-start-minimized
91 playlistVisible = false;
92 input_name = "";
93 b_interfaceFullScreen= false;
94 b_hasPausedWhenMinimized = false;
97 /* Ask for Privacy */
98 FirstRun::CheckAndRun( this, p_intf );
101 * Configuration and settings
102 * Pre-building of interface
104 /* Main settings */
105 setFocusPolicy( Qt::StrongFocus );
106 setAcceptDrops( true );
107 setWindowRole( "vlc-main" );
108 setWindowIcon( QApplication::windowIcon() );
109 setWindowOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
110 #ifdef Q_WS_MAC
111 setAttribute( Qt::WA_MacBrushedMetal );
112 #endif
114 /* Is video in embedded in the UI or not */
115 b_videoEmbedded = var_InheritBool( p_intf, "embedded-video" );
117 /* Does the interface resize to video size or the opposite */
118 b_autoresize = var_InheritBool( p_intf, "qt-video-autoresize" );
120 /* Are we in the enhanced always-video mode or not ? */
121 b_minimalView = var_InheritBool( p_intf, "qt-minimal-view" );
123 /* Do we want anoying popups or not */
124 b_notificationEnabled = var_InheritBool( p_intf, "qt-notification" );
126 /* */
127 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
129 /* Set the other interface settings */
130 settings = getSettings();
132 #ifdef WIN32
133 /* Volume keys */
134 p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
135 #endif
137 /* */
138 b_plDocked = getSettings()->value( "MainWindow/pl-dock-status", true ).toBool();
141 /**************************
142 * UI and Widgets design
143 **************************/
144 setVLCWindowsTitle();
146 /************
147 * Menu Bar *
148 ************/
149 VLCMenuBar::createMenuBar( this, p_intf );
150 CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
151 this, destroyPopupMenu() );
153 createMainWidget( settings );
155 /**************
156 * Status Bar *
157 **************/
158 createStatusBar();
159 setStatusBarVisibility( getSettings()->value( "MainWindow/status-bar-visible", false ).toBool() );
161 /********************
162 * Input Manager *
163 ********************/
164 MainInputManager::getInstance( p_intf );
166 #ifdef WIN32
167 himl = NULL;
168 p_taskbl = NULL;
169 taskbar_wmsg = RegisterWindowMessage("TaskbarButtonCreated");
170 #endif
172 /*********************************
173 * Create the Systray Management *
174 *********************************/
175 initSystray();
177 /*************************************************************
178 * Connect the input manager to the GUI elements it manages *
179 * Beware initSystray did some connects on input manager too *
180 *************************************************************/
182 * Connects on nameChanged()
183 * Those connects are different because options can impeach them to trigger.
185 /* Main Interface statusbar */
186 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
187 this, setName( const QString& ) );
188 /* and title of the Main Interface*/
189 if( var_InheritBool( p_intf, "qt-name-in-title" ) )
191 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
192 this, setVLCWindowsTitle( const QString& ) );
194 /* END CONNECTS ON IM */
196 /* VideoWidget connects for asynchronous calls */
197 b_videoFullScreen = false;
198 connect( this, SIGNAL(askGetVideo(WId*,int*,int*,unsigned*,unsigned *)),
199 this, SLOT(getVideoSlot(WId*,int*,int*,unsigned*,unsigned*)),
200 Qt::BlockingQueuedConnection );
201 connect( this, SIGNAL(askReleaseVideo( void )),
202 this, SLOT(releaseVideoSlot( void )),
203 Qt::BlockingQueuedConnection );
204 CONNECT( this, askVideoOnTop(bool), this, setVideoOnTop(bool));
206 if( videoWidget )
208 if( b_autoresize )
210 CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
211 this, setVideoSize( unsigned int, unsigned int ) );
212 CONNECT( videoWidget, sizeChanged( int, int ),
213 this, resizeStack( int, int ) );
215 CONNECT( this, askVideoSetFullScreen( bool ),
216 this, setVideoFullScreen( bool ) );
219 CONNECT( THEDP, toolBarConfUpdated(), this, recreateToolbars() );
221 CONNECT( this, askToQuit(), THEDP, quit() );
223 CONNECT( this, askBoss(), this, setBoss() );
224 CONNECT( this, askRaise(), this, setRaise() );
226 /** END of CONNECTS**/
229 /************
230 * Callbacks
231 ************/
232 var_AddCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
233 var_AddCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
234 var_AddCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
236 /* Register callback for the intf-popupmenu variable */
237 var_AddCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
240 /* Final Sizing, restoration and placement of the interface */
241 if( settings->value( "MainWindow/playlist-visible", false ).toBool() )
242 togglePlaylist();
244 QVLCTools::restoreWidgetPosition( settings, this, QSize(600, 420) );
246 b_interfaceFullScreen = isFullScreen();
248 setVisible( !b_hideAfterCreation );
250 computeMinimumSize();
252 /* Switch to minimal view if needed, must be called after the show() */
253 if( b_minimalView )
254 toggleMinimalView( true );
257 MainInterface::~MainInterface()
259 /* Unsure we hide the videoWidget before destroying it */
260 if( stackCentralOldWidget == videoWidget )
261 showTab( bgWidget );
263 if( videoWidget )
264 releaseVideoSlot();
266 #ifdef WIN32
267 if( himl )
268 ImageList_Destroy( himl );
269 if(p_taskbl)
270 p_taskbl->vt->Release(p_taskbl);
271 CoUninitialize();
272 #endif
274 /* Be sure to kill the actionsManager... Only used in the MI and control */
275 ActionsManager::killInstance();
277 /* Idem */
278 ExtensionsManager::killInstance();
280 /* Delete the FSC controller */
281 delete fullscreenControls;
283 /* Save states */
285 settings->beginGroup("MainWindow");
286 settings->setValue( "pl-dock-status", b_plDocked );
287 /* Save playlist state */
288 if( playlistWidget )
289 settings->setValue( "playlist-visible", playlistVisible );
291 settings->setValue( "adv-controls",
292 getControlsVisibilityStatus() & CONTROLS_ADVANCED );
293 settings->setValue( "status-bar-visible", b_statusbarVisible );
295 /* Save the stackCentralW sizes */
296 settings->setValue( "bgSize", stackWidgetsSizes[bgWidget] );
297 settings->setValue( "playlistSize", stackWidgetsSizes[playlistWidget] );
298 settings->endGroup();
300 /* Save this size */
301 QVLCTools::saveWidgetPosition(settings, this);
303 /* Save undocked playlist size */
304 if( playlistWidget && !isPlDocked() )
305 QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
307 delete playlistWidget;
309 delete statusBar();
311 /* Unregister callbacks */
312 var_DelCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
313 var_DelCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
314 var_DelCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
315 var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
317 p_intf->p_sys->p_mi = NULL;
320 void MainInterface::computeMinimumSize()
322 int minWidth = 30;
323 if( menuBar()->isVisible() )
324 minWidth += __MAX( controls->sizeHint().width(), menuBar()->sizeHint().width() );
326 setMinimumWidth( minWidth );
329 /*****************************
330 * Main UI handling *
331 *****************************/
332 void MainInterface::recreateToolbars()
334 bool b_adv = getControlsVisibilityStatus() & CONTROLS_ADVANCED;
336 delete controls;
337 delete inputC;
339 controls = new ControlsWidget( p_intf, b_adv, this );
340 inputC = new InputControlsWidget( p_intf, this );
341 mainLayout->insertWidget( 2, inputC );
342 mainLayout->insertWidget( settings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
343 controls );
345 if( fullscreenControls )
347 delete fullscreenControls;
348 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
349 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
350 this, handleKeyPress( QKeyEvent * ) );
354 void MainInterface::reloadPrefs()
356 b_notificationEnabled = var_InheritBool( p_intf, "qt-notification" );
357 b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
358 #ifdef WIN32
359 p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
360 #endif
361 if( !var_InheritBool( p_intf, "qt-fs-controller" ) && fullscreenControls )
363 delete fullscreenControls;
364 fullscreenControls = NULL;
368 void MainInterface::createMainWidget( QSettings *settings )
370 /* Create the main Widget and the mainLayout */
371 QWidget *main = new QWidget;
372 setCentralWidget( main );
373 mainLayout = new QVBoxLayout( main );
374 main->setContentsMargins( 0, 0, 0, 0 );
375 mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
377 /* */
378 stackCentralW = new QVLCStackedWidget( main );
380 /* Bg Cone */
381 bgWidget = new BackgroundWidget( p_intf );
382 stackCentralW->addWidget( bgWidget );
383 if ( !var_InheritBool( p_intf, "qt-bgcone" ) )
384 bgWidget->setWithArt( false );
385 else
386 if ( var_InheritBool( p_intf, "qt-bgcone-expands" ) )
387 bgWidget->setExpandstoHeight( true );
389 /* And video Outputs */
390 if( b_videoEmbedded )
392 videoWidget = new VideoWidget( p_intf );
393 stackCentralW->addWidget( videoWidget );
395 mainLayout->insertWidget( 1, stackCentralW );
397 stackWidgetsSizes[bgWidget] = settings->value( "MainWindow/bgSize", QSize( 600, 0 ) ).toSize();
398 /* Resize even if no-auto-resize, because we are at creation */
399 resizeStack( stackWidgetsSizes[bgWidget].width(), stackWidgetsSizes[bgWidget].height() );
401 /* Create the CONTROLS Widget */
402 controls = new ControlsWidget( p_intf,
403 settings->value( "MainWindow/adv-controls", false ).toBool(), this );
404 inputC = new InputControlsWidget( p_intf, this );
406 mainLayout->insertWidget( 2, inputC );
407 mainLayout->insertWidget( settings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
408 controls );
410 /* Visualisation, disabled for now, they SUCK */
411 #if 0
412 visualSelector = new VisualSelector( p_intf );
413 mainLayout->insertWidget( 0, visualSelector );
414 visualSelector->hide();
415 #endif
418 /* Enable the popup menu in the MI */
419 main->setContextMenuPolicy( Qt::CustomContextMenu );
420 CONNECT( main, customContextMenuRequested( const QPoint& ),
421 this, popupMenu( const QPoint& ) );
423 if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
424 /* Create the FULLSCREEN CONTROLS Widget */
425 if( var_InheritBool( p_intf, "qt-fs-controller" ) )
427 fullscreenControls = new FullscreenControllerWidget( p_intf, this );
428 CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
429 this, handleKeyPress( QKeyEvent * ) );
433 inline void MainInterface::initSystray()
435 bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
436 bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
438 if( var_InheritBool( p_intf, "qt-start-minimized") )
440 if( b_systrayAvailable )
442 b_systrayWanted = true;
443 b_hideAfterCreation = true;
445 else
446 msg_Err( p_intf, "cannot start minimized without system tray bar" );
449 if( b_systrayAvailable && b_systrayWanted )
450 createSystray();
453 inline void MainInterface::createStatusBar()
455 /****************
456 * Status Bar *
457 ****************/
458 /* Widgets Creation*/
459 QStatusBar *statusBarr = statusBar();
461 TimeLabel *timeLabel = new TimeLabel( p_intf );
462 nameLabel = new QLabel( this );
463 nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
464 | Qt::TextSelectableByKeyboard );
465 SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
467 /* Styling those labels */
468 timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
469 speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
470 nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
471 timeLabel->setStyleSheet(
472 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
473 speedLabel->setStyleSheet(
474 "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
475 /* pad both label and its tooltip */
476 nameLabel->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
478 /* and adding those */
479 statusBarr->addWidget( nameLabel, 8 );
480 statusBarr->addPermanentWidget( speedLabel, 0 );
481 statusBarr->addPermanentWidget( timeLabel, 0 );
483 /* timeLabel behaviour:
484 - double clicking opens the goto time dialog
485 - right-clicking and clicking just toggle between remaining and
486 elapsed time.*/
487 CONNECT( timeLabel, timeLabelDoubleClicked(), THEDP, gotoTimeDialog() );
489 CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
490 this, showCryptedLabel( bool ) );
492 CONNECT( THEMIM->getIM(), seekRequested( float ),
493 timeLabel, setDisplayPosition( float ) );
495 /* This shouldn't be necessary, but for somehow reason, the statusBarr
496 starts at height of 20px and when a text is shown it needs more space.
497 But, as the QMainWindow policy doesn't allow statusBar to change QMW's
498 geometry, we need to force a height. If you have a better idea, please
499 tell me -- jb
501 statusBarr->setFixedHeight( statusBarr->sizeHint().height() + 2 );
504 /**********************************************************************
505 * Handling of sizing of the components
506 **********************************************************************/
508 void MainInterface::debug()
510 #ifdef DEBUG_INTF
511 msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
512 msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
513 msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
515 msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
516 msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
517 msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
518 #endif
521 inline void MainInterface::showVideo() { showTab( videoWidget ); }
522 inline void MainInterface::restoreStackOldWidget()
523 { showTab( stackCentralOldWidget ); }
525 inline void MainInterface::showTab( QWidget *widget )
527 #ifdef DEBUG_INTF
528 msg_Warn( p_intf, "Old stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
529 #endif
531 stackCentralOldWidget = stackCentralW->currentWidget();
532 stackWidgetsSizes[stackCentralOldWidget] = stackCentralW->size();
534 /* If we are playing video, embedded */
535 if( videoWidget && THEMIM->getIM()->hasVideo() )
537 /* Video -> Playlist */
538 if( videoWidget == stackCentralOldWidget && widget == playlistWidget )
540 stackCentralW->removeWidget( videoWidget );
541 videoWidget->show(); videoWidget->raise();
544 /* Playlist -> Video */
545 if( playlistWidget == stackCentralOldWidget && widget == videoWidget )
547 playlistWidget->artContainer->removeWidget( videoWidget );
548 videoWidget->show(); videoWidget->raise();
549 stackCentralW->addWidget( videoWidget );
553 stackCentralW->setCurrentWidget( widget );
554 if( b_autoresize )
555 resizeStack( stackWidgetsSizes[widget].width(), stackWidgetsSizes[widget].height() );
557 #ifdef DEBUG_INTF
558 msg_Warn( p_intf, "State change %i", stackCentralW->currentIndex() );
559 msg_Warn( p_intf, "New stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
560 #endif
562 /* This part is done later, to account for the new pl size */
563 if( videoWidget && THEMIM->getIM()->hasVideo() &&
564 videoWidget == stackCentralOldWidget && widget == playlistWidget )
566 playlistWidget->artContainer->addWidget( videoWidget );
567 playlistWidget->artContainer->setCurrentWidget( videoWidget );
571 void MainInterface::destroyPopupMenu()
573 VLCMenuBar::PopupMenu( p_intf, false );
576 void MainInterface::popupMenu( const QPoint & )
578 VLCMenuBar::PopupMenu( p_intf, true );
581 void MainInterface::toggleFSC()
583 if( !fullscreenControls ) return;
585 IMEvent *eShow = new IMEvent( FullscreenControlToggle_Type );
586 QApplication::postEvent( fullscreenControls, eShow );
589 /****************************************************************************
590 * Video Handling
591 ****************************************************************************/
594 * NOTE:
595 * You must not change the state of this object or other Qt4 UI objects,
596 * from the video output thread - only from the Qt4 UI main loop thread.
597 * All window provider queries must be handled through signals or events.
598 * That's why we have all those emit statements...
600 WId MainInterface::getVideo( int *pi_x, int *pi_y,
601 unsigned int *pi_width, unsigned int *pi_height )
603 if( !videoWidget )
604 return 0;
606 /* This is a blocking call signal. Results are returned through pointers.
607 * Beware of deadlocks! */
608 WId id;
609 emit askGetVideo( &id, pi_x, pi_y, pi_width, pi_height );
610 return id;
613 void MainInterface::getVideoSlot( WId *p_id, int *pi_x, int *pi_y,
614 unsigned *pi_width, unsigned *pi_height )
616 /* Hidden or minimized, activate */
617 if( isHidden() || isMinimized() )
618 toggleUpdateSystrayMenu();
620 /* Request the videoWidget */
621 WId ret = videoWidget->request( pi_x, pi_y,
622 pi_width, pi_height, !b_autoresize );
623 *p_id = ret;
624 if( ret ) /* The videoWidget is available */
626 /* Consider the video active now */
627 showVideo();
629 /* Ask videoWidget to resize correctly, if we are in normal mode */
630 if( !isFullScreen() && !isMaximized() && b_autoresize )
631 videoWidget->SetSizing( *pi_width, *pi_height );
635 /* Asynchronous call from the WindowClose function */
636 void MainInterface::releaseVideo( void )
638 emit askReleaseVideo();
641 /* Function that is CONNECTED to the previous emit */
642 void MainInterface::releaseVideoSlot( void )
644 /* This function is called when the embedded video window is destroyed,
645 * or in the rare case that the embedded window is still here but the
646 * Qt4 interface exits. */
647 assert( videoWidget );
648 videoWidget->release();
649 setVideoOnTop( false );
650 setVideoFullScreen( false );
652 if( stackCentralW->currentWidget() == videoWidget )
653 restoreStackOldWidget();
654 else if( playlistWidget &&
655 playlistWidget->artContainer->currentWidget() == videoWidget )
657 playlistWidget->artContainer->setCurrentIndex( 0 );
658 stackCentralW->addWidget( videoWidget );
661 /* We don't want to have a blank video to popup */
662 stackCentralOldWidget = bgWidget;
665 void MainInterface::setVideoSize( unsigned int w, unsigned int h )
667 if( !isFullScreen() && !isMaximized() )
668 videoWidget->SetSizing( w, h );
671 void MainInterface::setVideoFullScreen( bool fs )
673 b_videoFullScreen = fs;
674 if( fs )
676 int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
677 /* if user hasn't defined screennumber, or screennumber that is bigger
678 * than current number of screens, take screennumber where current interface
679 * is
681 if( numscreen == -1 || numscreen > QApplication::desktop()->numScreens() )
682 numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
684 QRect screenres = QApplication::desktop()->screenGeometry( numscreen );
686 /* To be sure window is on proper-screen in xinerama */
687 if( !screenres.contains( pos() ) )
689 msg_Dbg( p_intf, "Moving video to correct screen");
690 move( QPoint( screenres.x(), screenres.y() ) );
693 /* */
694 if( playlistWidget != NULL && playlistWidget->artContainer->currentWidget() == videoWidget )
696 showTab( videoWidget );
699 /* */
700 setMinimalView( true );
701 setInterfaceFullScreen( true );
703 else
705 /* TODO do we want to restore screen and position ? (when
706 * qt-fullscreen-screennumber is forced) */
707 setMinimalView( b_minimalView );
708 setInterfaceFullScreen( b_interfaceFullScreen );
710 videoWidget->sync();
713 /* Slot to change the video always-on-top flag.
714 * Emit askVideoOnTop() to invoke this from other thread. */
715 void MainInterface::setVideoOnTop( bool on_top )
717 Qt::WindowFlags oldflags = windowFlags(), newflags;
719 if( on_top )
720 newflags = oldflags | Qt::WindowStaysOnTopHint;
721 else
722 newflags = oldflags & ~Qt::WindowStaysOnTopHint;
723 if( newflags != oldflags && !b_videoFullScreen )
726 setWindowFlags( newflags );
727 show(); /* necessary to apply window flags */
731 /* Asynchronous call from WindowControl function */
732 int MainInterface::controlVideo( int i_query, va_list args )
734 switch( i_query )
736 case VOUT_WINDOW_SET_SIZE:
738 unsigned int i_width = va_arg( args, unsigned int );
739 unsigned int i_height = va_arg( args, unsigned int );
741 emit askVideoToResize( i_width, i_height );
742 return VLC_SUCCESS;
744 case VOUT_WINDOW_SET_STATE:
746 unsigned i_arg = va_arg( args, unsigned );
747 unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
749 emit askVideoOnTop( on_top != 0 );
750 return VLC_SUCCESS;
752 case VOUT_WINDOW_SET_FULLSCREEN:
754 bool b_fs = va_arg( args, int );
756 emit askVideoSetFullScreen( b_fs );
757 return VLC_SUCCESS;
759 default:
760 msg_Warn( p_intf, "unsupported control query" );
761 return VLC_EGENERIC;
765 /*****************************************************************************
766 * Playlist, Visualisation and Menus handling
767 *****************************************************************************/
769 * Toggle the playlist widget or dialog
771 void MainInterface::createPlaylist()
773 playlistWidget = new PlaylistWidget( p_intf, this );
775 if( b_plDocked )
777 stackCentralW->addWidget( playlistWidget );
778 stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 600, 300 ) ).toSize();
780 else
782 #ifdef WIN32
783 playlistWidget->setParent( NULL );
784 #endif
785 playlistWidget->setWindowFlags( Qt::Window );
787 /* This will restore the geometry but will not work for position,
788 because of parenting */
789 QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
790 playlistWidget, QSize( 600, 300 ) );
794 void MainInterface::togglePlaylist()
796 if( !playlistWidget )
798 createPlaylist();
801 if( b_plDocked )
803 /* Playlist is not visible, show it */
804 if( stackCentralW->currentWidget() != playlistWidget )
806 showTab( playlistWidget );
808 else /* Hide it! */
810 restoreStackOldWidget();
812 playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
814 else
816 #ifdef WIN32
817 playlistWidget->setParent( NULL );
818 #endif
819 playlistWidget->setWindowFlags( Qt::Window );
820 playlistVisible = !playlistVisible;
821 playlistWidget->setVisible( playlistVisible );
823 debug();
826 void MainInterface::dockPlaylist( bool p_docked )
828 if( b_plDocked == p_docked ) return;
829 b_plDocked = p_docked;
831 if( !playlistWidget ) return; /* Playlist wasn't created yet */
832 if( !p_docked )
834 stackCentralW->removeWidget( playlistWidget );
835 #ifdef WIN32
836 playlistWidget->setParent( NULL );
837 #endif
838 playlistWidget->setWindowFlags( Qt::Window );
839 QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
840 playlistWidget, QSize( 600, 300 ) );
841 playlistWidget->show();
842 restoreStackOldWidget();
844 else
846 QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
847 playlistWidget->setWindowFlags( Qt::Widget ); // Probably a Qt bug here
848 // It would be logical that QStackWidget::addWidget reset the flags...
849 stackCentralW->addWidget( playlistWidget );
850 showTab( playlistWidget );
852 playlistVisible = true;
856 * setMinimalView is the private function used by
857 * the SLOT toggleMinimalView and setVideoFullScreen
859 void MainInterface::setMinimalView( bool b_minimal )
861 menuBar()->setVisible( !b_minimal );
862 controls->setVisible( !b_minimal );
863 statusBar()->setVisible( !b_minimal && b_statusbarVisible );
864 inputC->setVisible( !b_minimal );
868 * This public SLOT is used for moving to minimal View Mode
870 * If b_minimal is false, then we are normalView
872 void MainInterface::toggleMinimalView( bool b_minimal )
874 if( !b_minimalView && b_autoresize ) /* Normal mode */
876 if( stackCentralW->currentWidget() == bgWidget )
878 if( stackCentralW->height() < 16 )
880 resizeStack( stackCentralW->width(), 100 );
884 b_minimalView = b_minimal;
885 if( !b_videoFullScreen )
887 setMinimalView( b_minimalView );
888 computeMinimumSize();
891 emit minimalViewToggled( b_minimalView );
894 /* toggling advanced controls buttons */
895 void MainInterface::toggleAdvancedButtons()
897 controls->toggleAdvanced();
898 // if( fullscreenControls ) fullscreenControls->toggleAdvanced();
901 /* Get the visibility status of the controls (hidden or not, advanced or not) */
902 int MainInterface::getControlsVisibilityStatus()
904 if( !controls ) return 0;
905 return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
906 + CONTROLS_ADVANCED * controls->b_advancedVisible );
909 void MainInterface::setStatusBarVisibility( bool b_visible )
911 statusBar()->setVisible( b_visible );
912 b_statusbarVisible = b_visible;
913 if( controls ) controls->setGripVisible( !b_statusbarVisible );
916 #if 0
917 void MainInterface::visual()
919 if( !VISIBLE( visualSelector) )
921 visualSelector->show();
922 if( !THEMIM->getIM()->hasVideo() )
924 /* Show the background widget */
926 visualSelectorEnabled = true;
928 else
930 /* Stop any currently running visualization */
931 visualSelector->hide();
932 visualSelectorEnabled = false;
935 #endif
937 /************************************************************************
938 * Other stuff
939 ************************************************************************/
940 void MainInterface::setName( const QString& name )
942 input_name = name; /* store it for the QSystray use */
943 /* Display it in the status bar, but also as a Tooltip in case it doesn't
944 fit in the label */
945 nameLabel->setText( name );
946 nameLabel->setToolTip( name );
950 * Give the decorations of the Main Window a correct Name.
951 * If nothing is given, set it to VLC...
953 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
955 if( aTitle.isEmpty() )
957 setWindowTitle( qtr( "VLC media player" ) );
959 else
961 setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
965 void MainInterface::showCryptedLabel( bool b_show )
967 if( cryptedLabel == NULL )
969 cryptedLabel = new QLabel;
970 // The lock icon is not the right one for DRM protection/scrambled.
971 //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
972 cryptedLabel->setText( "DRM" );
973 statusBar()->addWidget( cryptedLabel );
976 cryptedLabel->setVisible( b_show );
979 void MainInterface::showBuffering( float f_cache )
981 QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
982 statusBar()->showMessage( amount, 1000 );
985 /*****************************************************************************
986 * Systray Icon and Systray Menu
987 *****************************************************************************/
989 * Create a SystemTray icon and a menu that would go with it.
990 * Connects to a click handler on the icon.
992 void MainInterface::createSystray()
994 QIcon iconVLC;
995 if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
996 iconVLC = QIcon( ":/logo/vlc128-xmas.png" );
997 else
998 iconVLC = QIcon( ":/logo/vlc128.png" );
999 sysTray = new QSystemTrayIcon( iconVLC, this );
1000 sysTray->setToolTip( qtr( "VLC media player" ));
1002 systrayMenu = new QMenu( qtr( "VLC media player" ), this );
1003 systrayMenu->setIcon( iconVLC );
1005 VLCMenuBar::updateSystrayMenu( this, p_intf, true );
1006 sysTray->show();
1008 CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
1009 this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
1011 /* Connects on nameChanged() */
1012 CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
1013 this, updateSystrayTooltipName( const QString& ) );
1014 /* Connect PLAY_STATUS on the systray */
1015 CONNECT( THEMIM->getIM(), playingStatusChanged( int ),
1016 this, updateSystrayTooltipStatus( int ) );
1020 * Updates the Systray Icon's menu and toggle the main interface
1022 void MainInterface::toggleUpdateSystrayMenu()
1024 /* If hidden, show it */
1025 if( isHidden() )
1027 show();
1028 activateWindow();
1030 else if( isMinimized() )
1032 /* Minimized */
1033 showNormal();
1034 activateWindow();
1036 else
1038 /* Visible (possibly under other windows) */
1039 #ifdef WIN32
1040 /* check if any visible window is above vlc in the z-order,
1041 * but ignore the ones always on top
1042 * and the ones which can't be activated */
1043 WINDOWINFO wi;
1044 HWND hwnd;
1045 wi.cbSize = sizeof( WINDOWINFO );
1046 for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
1047 hwnd && ( !IsWindowVisible( hwnd ) ||
1048 ( GetWindowInfo( hwnd, &wi ) &&
1049 (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
1050 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
1051 if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
1052 (wi.dwExStyle&WS_EX_TOPMOST) )
1054 hide();
1056 else
1058 activateWindow();
1060 #else
1061 hide();
1062 #endif
1064 if( sysTray )
1065 VLCMenuBar::updateSystrayMenu( this, p_intf );
1068 /* First Item of the systray menu */
1069 void MainInterface::showUpdateSystrayMenu()
1071 if( isHidden() )
1072 show();
1073 if( isMinimized() )
1074 showNormal();
1075 activateWindow();
1077 VLCMenuBar::updateSystrayMenu( this, p_intf );
1080 /* First Item of the systray menu */
1081 void MainInterface::hideUpdateSystrayMenu()
1083 hide();
1084 VLCMenuBar::updateSystrayMenu( this, p_intf );
1087 /* Click on systray Icon */
1088 void MainInterface::handleSystrayClick(
1089 QSystemTrayIcon::ActivationReason reason )
1091 switch( reason )
1093 case QSystemTrayIcon::Trigger:
1094 case QSystemTrayIcon::DoubleClick:
1095 #ifdef Q_WS_MAC
1096 VLCMenuBar::updateSystrayMenu( this, p_intf );
1097 #else
1098 toggleUpdateSystrayMenu();
1099 #endif
1100 break;
1101 case QSystemTrayIcon::MiddleClick:
1102 sysTray->showMessage( qtr( "VLC media player" ),
1103 qtr( "Control menu for the player" ),
1104 QSystemTrayIcon::Information, 3000 );
1105 break;
1106 default:
1107 break;
1112 * Updates the name of the systray Icon tooltip.
1113 * Doesn't check if the systray exists, check before you call it.
1115 void MainInterface::updateSystrayTooltipName( const QString& name )
1117 if( name.isEmpty() )
1119 sysTray->setToolTip( qtr( "VLC media player" ) );
1121 else
1123 sysTray->setToolTip( name );
1124 if( b_notificationEnabled && ( isHidden() || isMinimized() ) )
1126 sysTray->showMessage( qtr( "VLC media player" ), name,
1127 QSystemTrayIcon::NoIcon, 3000 );
1131 VLCMenuBar::updateSystrayMenu( this, p_intf );
1135 * Updates the status of the systray Icon tooltip.
1136 * Doesn't check if the systray exists, check before you call it.
1138 void MainInterface::updateSystrayTooltipStatus( int i_status )
1140 switch( i_status )
1142 case PLAYING_S:
1143 sysTray->setToolTip( input_name );
1144 break;
1145 case PAUSE_S:
1146 sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1147 break;
1148 default:
1149 sysTray->setToolTip( qtr( "VLC media player" ) );
1150 break;
1152 VLCMenuBar::updateSystrayMenu( this, p_intf );
1155 void MainInterface::changeEvent(QEvent *event)
1157 if( event->type() == QEvent::WindowStateChange )
1159 QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
1160 Qt::WindowStates newState = windowState();
1161 Qt::WindowStates oldState = windowStateChangeEvent->oldState();
1163 if( newState & Qt::WindowMinimized )
1165 b_hasPausedWhenMinimized = false;
1167 if( THEMIM->getIM()->playingStatus() == PLAYING_S &&
1168 THEMIM->getIM()->hasVideo() && !THEMIM->getIM()->hasVisualisation() &&
1169 b_pauseOnMinimize )
1171 b_hasPausedWhenMinimized = true;
1172 THEMIM->pause();
1175 else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
1177 if( b_hasPausedWhenMinimized )
1179 THEMIM->play();
1184 QWidget::changeEvent(event);
1187 /************************************************************************
1188 * D&D Events
1189 ************************************************************************/
1190 void MainInterface::dropEvent(QDropEvent *event)
1192 dropEventPlay( event, true );
1196 * dropEventPlay
1198 * Event called if something is dropped onto a VLC window
1199 * \param event the event in question
1200 * \param b_play whether to play the file immediately
1201 * \param b_playlist true to add to playlist, false to add to media library
1202 * \return nothing
1204 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play, bool b_playlist )
1206 if( event->possibleActions() & ( Qt::CopyAction | Qt::MoveAction ) )
1207 event->setDropAction( Qt::CopyAction );
1208 else
1209 return;
1211 const QMimeData *mimeData = event->mimeData();
1213 /* D&D of a subtitles file, add it on the fly */
1214 if( mimeData->urls().count() == 1 && THEMIM->getIM()->hasInput() )
1216 if( !input_AddSubtitle( THEMIM->getInput(),
1217 qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1218 true ) )
1220 event->accept();
1221 return;
1225 bool first = b_play;
1226 foreach( const QUrl &url, mimeData->urls() )
1228 if( url.isValid() )
1230 QString mrl = toURI( url.toEncoded().constData() );
1231 playlist_Add( THEPL, qtu(mrl), NULL,
1232 PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1233 PLAYLIST_END, b_playlist, pl_Unlocked );
1234 first = false;
1235 RecentsMRL::getInstance( p_intf )->addRecent( mrl );
1239 /* Browsers give content as text if you dnd the addressbar,
1240 so check if mimedata has valid url in text and use it
1241 if we didn't get any normal Urls()*/
1242 if( !mimeData->hasUrls() && mimeData->hasText() &&
1243 QUrl(mimeData->text()).isValid() )
1245 QString mrl = toURI( mimeData->text() );
1246 playlist_Add( THEPL, qtu(mrl), NULL,
1247 PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1248 PLAYLIST_END, b_playlist, pl_Unlocked );
1250 event->accept();
1252 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1254 event->acceptProposedAction();
1256 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1258 event->acceptProposedAction();
1260 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1262 event->accept();
1265 /************************************************************************
1266 * Events stuff
1267 ************************************************************************/
1268 void MainInterface::keyPressEvent( QKeyEvent *e )
1270 handleKeyPress( e );
1273 void MainInterface::handleKeyPress( QKeyEvent *e )
1275 if( ( e->modifiers() & Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) )
1277 toggleMinimalView( !b_minimalView );
1278 e->accept();
1281 int i_vlck = qtEventToVLCKey( e );
1282 if( i_vlck > 0 )
1284 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1285 e->accept();
1287 else
1288 e->ignore();
1291 void MainInterface::wheelEvent( QWheelEvent *e )
1293 int i_vlckey = qtWheelEventToVLCKey( e );
1294 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1295 e->accept();
1298 void MainInterface::closeEvent( QCloseEvent *e )
1300 // hide();
1301 emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
1302 /* Accept session quit. Otherwise we break the desktop mamager. */
1303 e->accept();
1306 void MainInterface::setInterfaceFullScreen( bool fs )
1308 if( fs )
1309 setWindowState( windowState() | Qt::WindowFullScreen );
1310 else
1311 setWindowState( windowState() & ~Qt::WindowFullScreen );
1313 void MainInterface::toggleInterfaceFullScreen()
1315 b_interfaceFullScreen = !b_interfaceFullScreen;
1316 if( !b_videoFullScreen )
1317 setInterfaceFullScreen( b_interfaceFullScreen );
1318 emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1321 void MainInterface::emitBoss()
1323 emit askBoss();
1325 void MainInterface::setBoss()
1327 THEMIM->pause();
1328 if( sysTray )
1330 hide();
1332 else
1334 showMinimized();
1338 void MainInterface::emitRaise()
1340 emit askRaise();
1342 void MainInterface::setRaise()
1344 activateWindow();
1345 raise();
1348 /*****************************************************************************
1349 * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1350 * We don't show the menu directly here because we don't want the
1351 * caller to block for a too long time.
1352 *****************************************************************************/
1353 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1354 vlc_value_t old_val, vlc_value_t new_val, void *param )
1356 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1358 intf_thread_t *p_intf = (intf_thread_t *)param;
1360 if( p_intf->pf_show_dialog )
1362 p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1363 new_val.b_bool, NULL );
1366 return VLC_SUCCESS;
1369 /*****************************************************************************
1370 * IntfShowCB: callback triggered by the intf-toggle-fscontrol libvlc variable.
1371 *****************************************************************************/
1372 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1373 vlc_value_t old_val, vlc_value_t new_val, void *param )
1375 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1376 VLC_UNUSED( new_val );
1378 intf_thread_t *p_intf = (intf_thread_t *)param;
1379 p_intf->p_sys->p_mi->toggleFSC();
1381 /* Show event */
1382 return VLC_SUCCESS;
1385 /*****************************************************************************
1386 * IntfRaiseMainCB: callback triggered by the intf-show-main libvlc variable.
1387 *****************************************************************************/
1388 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
1389 vlc_value_t old_val, vlc_value_t new_val, void *param )
1391 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1392 VLC_UNUSED( new_val );
1394 intf_thread_t *p_intf = (intf_thread_t *)param;
1395 p_intf->p_sys->p_mi->emitRaise();
1397 return VLC_SUCCESS;
1400 /*****************************************************************************
1401 * IntfBossCB: callback triggered by the intf-boss libvlc variable.
1402 *****************************************************************************/
1403 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
1404 vlc_value_t old_val, vlc_value_t new_val, void *param )
1406 VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1407 VLC_UNUSED( new_val );
1409 intf_thread_t *p_intf = (intf_thread_t *)param;
1410 p_intf->p_sys->p_mi->emitBoss();
1412 return VLC_SUCCESS;