]> git.sesse.net Git - vlc/blob - modules/gui/qt4/main_interface.cpp
Qt: fix playback start if VLC was minimized
[vlc] / modules / gui / qt4 / main_interface.cpp
1 /*****************************************************************************
2  * main_interface.cpp : Main interface
3  ****************************************************************************
4  * Copyright (C) 2006-2010 VideoLAN and AUTHORS
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
8  *          Jean-Baptiste Kempf <jb@videolan.org>
9  *          Ilkka Ollakka <ileoo@videolan.org>
10  *
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.
15  *
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.
20  *
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  *****************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include "qt4.hpp"
31
32 #include "main_interface.hpp"
33 #include "input_manager.hpp"                    // Creation
34 #include "actions_manager.hpp"                  // killInstance
35 #include "extensions_manager.hpp"               // killInstance
36
37 #include "util/customwidgets.hpp"               // qtEventToVLCKey, QVLCStackedWidget
38 #include "util/qt_dirs.hpp"                     // toNativeSeparators
39
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
45 #include "menus.hpp"                            // Menu creation
46 #include "recents.hpp"                          // RecentItems when DnD
47
48 #include <QCloseEvent>
49 #include <QKeyEvent>
50
51 #include <QUrl>
52 #include <QSize>
53 #include <QDate>
54
55 #include <QMenu>
56 #include <QMenuBar>
57 #include <QStatusBar>
58 #include <QLabel>
59 #include <QStackedWidget>
60
61 #include <vlc_keys.h>                       /* Wheel event */
62 #include <vlc_vout_display.h>               /* vout_thread_t and VOUT_ events */
63
64 // #define DEBUG_INTF
65
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
72 MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
73 {
74     /* Variables initialisation */
75     bgWidget             = NULL;
76     videoWidget          = NULL;
77     playlistWidget       = NULL;
78     stackCentralOldWidget= NULL;
79 #ifndef HAVE_MAEMO
80     sysTray              = NULL;
81 #endif
82     fullscreenControls   = NULL;
83     cryptedLabel         = NULL;
84     controls             = NULL;
85     inputC               = NULL;
86
87     b_hideAfterCreation  = false; // --qt-start-minimized
88     playlistVisible      = false;
89     input_name           = "";
90
91
92     /* Ask for Privacy */
93     FirstRun::CheckAndRun( this, p_intf );
94
95     /**
96      *  Configuration and settings
97      *  Pre-building of interface
98      **/
99     /* Main settings */
100     setFocusPolicy( Qt::StrongFocus );
101     setAcceptDrops( true );
102     setWindowRole( "vlc-main" );
103     setWindowIcon( QApplication::windowIcon() );
104     setWindowOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
105 #ifdef Q_WS_MAC
106     setAttribute( Qt::WA_MacBrushedMetal );
107 #endif
108
109     /* Is video in embedded in the UI or not */
110     b_videoEmbedded = var_InheritBool( p_intf, "embedded-video" );
111
112     /* Does the interface resize to video size or the opposite */
113     b_autoresize = var_InheritBool( p_intf, "qt-video-autoresize" );
114
115     /* Are we in the enhanced always-video mode or not ? */
116     b_minimalView = var_InheritBool( p_intf, "qt-minimal-view" );
117
118     /* Do we want anoying popups or not */
119     b_notificationEnabled = var_InheritBool( p_intf, "qt-notification" );
120
121     /* Set the other interface settings */
122     settings = getSettings();
123     settings->beginGroup( "MainWindow" );
124
125 #ifdef WIN32
126     /* Volume keys */
127     p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
128 #endif
129
130     /* */
131     b_plDocked = getSettings()->value( "pl-dock-status", true ).toBool();
132
133     settings->endGroup( );
134
135     /*********************************
136      * Create the Systray Management *
137      *********************************/
138     initSystray();
139
140     /**************************
141      *  UI and Widgets design
142      **************************/
143     setVLCWindowsTitle();
144
145     /************
146      * Menu Bar *
147      ************/
148     QVLCMenu::createMenuBar( this, p_intf );
149     CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
150              this, destroyPopupMenu() );
151
152     createMainWidget( settings );
153
154     /**************
155      * Status Bar *
156      **************/
157     createStatusBar();
158     setStatusBarVisibility( getSettings()->value( "MainWindow/status-bar-visible", false ).toBool() );
159
160     /********************
161      * Input Manager    *
162      ********************/
163     MainInputManager::getInstance( p_intf );
164
165 #ifdef WIN32
166     himl = NULL;
167     p_taskbl = NULL;
168     taskbar_wmsg = RegisterWindowMessage("TaskbarButtonCreated");
169 #endif
170
171     /************************************************************
172      * Connect the input manager to the GUI elements it manages *
173      ************************************************************/
174     /**
175      * Connects on nameChanged()
176      * Those connects are different because options can impeach them to trigger.
177      **/
178     /* Main Interface statusbar */
179     CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
180              this, setName( const QString& ) );
181     /* and systray */
182 #ifndef HAVE_MAEMO
183     if( sysTray )
184     {
185         CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
186                  this, updateSystrayTooltipName( const QString& ) );
187     }
188 #endif
189     /* and title of the Main Interface*/
190     if( var_InheritBool( p_intf, "qt-name-in-title" ) )
191     {
192         CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
193                  this, setVLCWindowsTitle( const QString& ) );
194     }
195
196     /**
197      * CONNECTS on PLAY_STATUS
198      **/
199     /* Status on the systray */
200 #ifndef HAVE_MAEMO
201     if( sysTray )
202     {
203         CONNECT( THEMIM->getIM(), playingStatusChanged( int ),
204                  this, updateSystrayTooltipStatus( int ) );
205     }
206 #endif
207
208     /* END CONNECTS ON IM */
209
210     /* VideoWidget connects for asynchronous calls */
211     b_videoFullScreen = false;
212     connect( this, SIGNAL(askGetVideo(WId*,int*,int*,unsigned*,unsigned *)),
213              this, SLOT(getVideoSlot(WId*,int*,int*,unsigned*,unsigned*)),
214              Qt::BlockingQueuedConnection );
215     connect( this, SIGNAL(askReleaseVideo( void )),
216              this, SLOT(releaseVideoSlot( void )),
217              Qt::BlockingQueuedConnection );
218     CONNECT( this, askVideoOnTop(bool), this, setVideoOnTop(bool));
219
220     if( videoWidget )
221     {
222         if( b_autoresize )
223         {
224             CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
225                      this, setVideoSize( unsigned int, unsigned int ) );
226             CONNECT( videoWidget, sizeChanged( int, int ),
227                      this, resizeStack( int,  int ) );
228         }
229         CONNECT( this, askVideoSetFullScreen( bool ),
230                  this, setVideoFullScreen( bool ) );
231     }
232
233     CONNECT( THEDP, toolBarConfUpdated(), this, recreateToolbars() );
234
235     CONNECT( this, askToQuit(), THEDP, quit() );
236
237     /** END of CONNECTS**/
238
239
240     /************
241      * Callbacks
242      ************/
243     var_AddCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );
244
245     /* Register callback for the intf-popupmenu variable */
246     var_AddCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
247
248     /* Playlist */
249     int i_plVis = settings->value( "MainWindow/playlist-visible", false ).toBool();
250
251     if( i_plVis ) togglePlaylist();
252
253     /**** FINAL SIZING and placement of interface */
254     settings->beginGroup( "MainWindow" );
255     QVLCTools::restoreWidgetPosition( settings, this, QSize(600, 420) );
256     settings->endGroup();
257
258     b_interfaceFullScreen = isFullScreen();
259
260     /* Final sizing and showing */
261     setVisible( !b_hideAfterCreation );
262
263     computeMinimumSize();
264
265     /* Switch to minimal view if needed, must be called after the show() */
266     if( b_minimalView )
267         toggleMinimalView( true );
268
269     b_hasPausedWhenMinimized = false;
270 }
271
272 MainInterface::~MainInterface()
273 {
274     /* Unsure we hide the videoWidget before destroying it */
275     if( stackCentralOldWidget == videoWidget )
276         showTab( bgWidget );
277
278     if( videoWidget )
279         releaseVideoSlot();
280
281 #ifdef WIN32
282     if( himl )
283         ImageList_Destroy( himl );
284     if(p_taskbl)
285         p_taskbl->vt->Release(p_taskbl);
286     CoUninitialize();
287 #endif
288
289     /* Be sure to kill the actionsManager... Only used in the MI and control */
290     ActionsManager::killInstance();
291
292     /* Idem */
293     ExtensionsManager::killInstance();
294
295     /* Delete the FSC controller */
296     delete fullscreenControls;
297
298     /* Save states */
299     settings->beginGroup( "MainWindow" );
300
301     settings->setValue( "pl-dock-status", b_plDocked );
302     /* Save playlist state */
303     if( playlistWidget )
304         settings->setValue( "playlist-visible", playlistVisible );
305
306     settings->setValue( "adv-controls",
307                         getControlsVisibilityStatus() & CONTROLS_ADVANCED );
308     settings->setValue( "status-bar-visible", b_statusbarVisible );
309
310     /* Save the stackCentralW sizes */
311     settings->setValue( "bgSize", stackWidgetsSizes[bgWidget] );
312     settings->setValue( "playlistSize", stackWidgetsSizes[playlistWidget] );
313
314     /* Save this size */
315     QVLCTools::saveWidgetPosition(settings, this);
316
317     settings->endGroup();
318
319     /* Save undocked playlist size */
320     if( playlistWidget && !isPlDocked() )
321         QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
322
323     delete playlistWidget;
324
325     delete statusBar();
326
327     /* Unregister callbacks */
328     var_DelCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );
329     var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
330
331     p_intf->p_sys->p_mi = NULL;
332 }
333
334 void MainInterface::computeMinimumSize()
335 {
336     int minWidth = 30;
337     if( menuBar()->isVisible() )
338         minWidth += __MAX( controls->sizeHint().width(), menuBar()->sizeHint().width() );
339
340     setMinimumWidth( minWidth );
341 }
342
343 /*****************************
344  *   Main UI handling        *
345  *****************************/
346 void MainInterface::recreateToolbars()
347 {
348     bool b_adv = getControlsVisibilityStatus() & CONTROLS_ADVANCED;
349
350     settings->beginGroup( "MainWindow" );
351     delete controls;
352     delete inputC;
353
354     controls = new ControlsWidget( p_intf, b_adv, this );
355     inputC = new InputControlsWidget( p_intf, this );
356
357     if( fullscreenControls )
358     {
359         delete fullscreenControls;
360         fullscreenControls = new FullscreenControllerWidget( p_intf, this );
361         CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
362                  this, handleKeyPress( QKeyEvent * ) );
363     }
364     mainLayout->insertWidget( 2, inputC );
365     mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
366                               controls );
367     settings->endGroup();
368 }
369
370 void MainInterface::createMainWidget( QSettings *settings )
371 {
372     /* Create the main Widget and the mainLayout */
373     QWidget *main = new QWidget;
374     setCentralWidget( main );
375     mainLayout = new QVBoxLayout( main );
376     main->setContentsMargins( 0, 0, 0, 0 );
377     mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
378
379     /* */
380     stackCentralW = new QVLCStackedWidget( main );
381
382     /* Bg Cone */
383     bgWidget = new BackgroundWidget( p_intf );
384     stackCentralW->addWidget( bgWidget );
385     if ( !var_InheritBool( p_intf, "qt-bgcone" ) )
386         bgWidget->setWithArt( false );
387     else
388         if ( var_InheritBool( p_intf, "qt-bgcone-expands" ) )
389             bgWidget->setExpandstoHeight( true );
390
391     /* And video Outputs */
392     if( b_videoEmbedded )
393     {
394         videoWidget = new VideoWidget( p_intf );
395         stackCentralW->addWidget( videoWidget );
396     }
397     mainLayout->insertWidget( 1, stackCentralW );
398
399     settings->beginGroup( "MainWindow" );
400     stackWidgetsSizes[bgWidget] = settings->value( "bgSize", QSize( 600, 0 ) ).toSize();
401     /* Resize even if no-auto-resize, because we are at creation */
402     resizeStack( stackWidgetsSizes[bgWidget].width(), stackWidgetsSizes[bgWidget].height() );
403
404     /* Create the CONTROLS Widget */
405     controls = new ControlsWidget( p_intf,
406                    settings->value( "adv-controls", false ).toBool(), this );
407     inputC = new InputControlsWidget( p_intf, this );
408
409     mainLayout->insertWidget( 2, inputC );
410     mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
411                               controls );
412
413     /* Visualisation, disabled for now, they SUCK */
414     #if 0
415     visualSelector = new VisualSelector( p_intf );
416     mainLayout->insertWidget( 0, visualSelector );
417     visualSelector->hide();
418     #endif
419
420     settings->endGroup();
421
422     /* Enable the popup menu in the MI */
423     main->setContextMenuPolicy( Qt::CustomContextMenu );
424     CONNECT( main, customContextMenuRequested( const QPoint& ),
425              this, popupMenu( const QPoint& ) );
426
427     if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
428         /* Create the FULLSCREEN CONTROLS Widget */
429         if( var_InheritBool( p_intf, "qt-fs-controller" ) )
430         {
431             fullscreenControls = new FullscreenControllerWidget( p_intf, this );
432             CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
433                      this, handleKeyPress( QKeyEvent * ) );
434         }
435 }
436
437 inline void MainInterface::initSystray()
438 {
439 #ifndef HAVE_MAEMO
440     bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
441     bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
442
443     if( var_InheritBool( p_intf, "qt-start-minimized") )
444     {
445         if( b_systrayAvailable )
446         {
447             b_systrayWanted = true;
448             b_hideAfterCreation = true;
449         }
450         else
451             msg_Err( p_intf, "cannot start minimized without system tray bar" );
452     }
453
454     if( b_systrayAvailable && b_systrayWanted )
455         createSystray();
456 #endif
457 }
458
459 inline void MainInterface::createStatusBar()
460 {
461     /****************
462      *  Status Bar  *
463      ****************/
464     /* Widgets Creation*/
465     QStatusBar *statusBarr = statusBar();
466
467     TimeLabel *timeLabel = new TimeLabel( p_intf );
468     nameLabel = new QLabel( this );
469     nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
470                                       | Qt::TextSelectableByKeyboard );
471     SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
472
473     /* Styling those labels */
474     timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
475     speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
476     nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
477     timeLabel->setStyleSheet(
478             "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
479     speedLabel->setStyleSheet(
480             "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
481     /* pad both label and its tooltip */
482     nameLabel->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
483
484     /* and adding those */
485     statusBarr->addWidget( nameLabel, 8 );
486     statusBarr->addPermanentWidget( speedLabel, 0 );
487     statusBarr->addPermanentWidget( timeLabel, 0 );
488
489     /* timeLabel behaviour:
490        - double clicking opens the goto time dialog
491        - right-clicking and clicking just toggle between remaining and
492          elapsed time.*/
493     CONNECT( timeLabel, timeLabelDoubleClicked(), THEDP, gotoTimeDialog() );
494
495     CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
496              this, showCryptedLabel( bool ) );
497
498     CONNECT( THEMIM->getIM(), seekRequested( float ),
499              timeLabel, setDisplayPosition( float ) );
500
501     /* This shouldn't be necessary, but for somehow reason, the statusBarr
502        starts at height of 20px and when a text is shown it needs more space.
503        But, as the QMainWindow policy doesn't allow statusBar to change QMW's
504        geometry, we need to force a height. If you have a better idea, please
505        tell me -- jb
506      */
507     statusBarr->setFixedHeight( statusBarr->sizeHint().height() + 2 );
508 }
509
510 /**********************************************************************
511  * Handling of sizing of the components
512  **********************************************************************/
513
514 void MainInterface::debug()
515 {
516 #ifdef DEBUG_INTF
517     msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
518     msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
519     msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
520
521     msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
522     msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
523     msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
524 #endif
525 }
526
527 inline void MainInterface::showVideo() { showTab( videoWidget ); }
528 inline void MainInterface::restoreStackOldWidget()
529             { showTab( stackCentralOldWidget ); }
530
531 inline void MainInterface::showTab( QWidget *widget )
532 {
533 #ifdef DEBUG_INTF
534     msg_Warn( p_intf, "Old stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
535 #endif
536
537     stackCentralOldWidget = stackCentralW->currentWidget();
538     stackWidgetsSizes[stackCentralOldWidget] = stackCentralW->size();
539
540     stackCentralW->setCurrentWidget( widget );
541     if( b_autoresize )
542         resizeStack( stackWidgetsSizes[widget].width(), stackWidgetsSizes[widget].height() );
543
544 #ifdef DEBUG_INTF
545     msg_Warn( p_intf, "State change %i",  stackCentralW->currentIndex() );
546     msg_Warn( p_intf, "New stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
547 #endif
548 }
549
550 void MainInterface::destroyPopupMenu()
551 {
552     QVLCMenu::PopupMenu( p_intf, false );
553 }
554
555 void MainInterface::popupMenu( const QPoint & )
556 {
557     QVLCMenu::PopupMenu( p_intf, true );
558 }
559
560 void MainInterface::toggleFSC()
561 {
562    if( !fullscreenControls ) return;
563
564    IMEvent *eShow = new IMEvent( FullscreenControlToggle_Type );
565    QApplication::postEvent( fullscreenControls, eShow );
566 }
567
568 /****************************************************************************
569  * Video Handling
570  ****************************************************************************/
571
572 /**
573  * NOTE:
574  * You must not change the state of this object or other Qt4 UI objects,
575  * from the video output thread - only from the Qt4 UI main loop thread.
576  * All window provider queries must be handled through signals or events.
577  * That's why we have all those emit statements...
578  */
579 WId MainInterface::getVideo( int *pi_x, int *pi_y,
580                              unsigned int *pi_width, unsigned int *pi_height )
581 {
582     if( !videoWidget )
583         return 0;
584
585     /* This is a blocking call signal. Results are returned through pointers.
586      * Beware of deadlocks! */
587     WId id;
588     emit askGetVideo( &id, pi_x, pi_y, pi_width, pi_height );
589     return id;
590 }
591
592 void MainInterface::getVideoSlot( WId *p_id, int *pi_x, int *pi_y,
593                                   unsigned *pi_width, unsigned *pi_height )
594 {
595     /* Hidden or minimized, activate */
596     if( isHidden() || isMinimized() )
597         toggleUpdateSystrayMenu();
598
599     /* Request the videoWidget */
600     WId ret = videoWidget->request( pi_x, pi_y,
601                                     pi_width, pi_height, !b_autoresize );
602     *p_id = ret;
603     if( ret ) /* The videoWidget is available */
604     {
605         /* Consider the video active now */
606         showVideo();
607
608         /* Ask videoWidget to resize correctly, if we are in normal mode */
609         if( !isFullScreen() && !isMaximized() && b_autoresize )
610             videoWidget->SetSizing( *pi_width, *pi_height );
611     }
612 }
613
614 /* Asynchronous call from the WindowClose function */
615 void MainInterface::releaseVideo( void )
616 {
617     emit askReleaseVideo();
618 }
619
620 /* Function that is CONNECTED to the previous emit */
621 void MainInterface::releaseVideoSlot( void )
622 {
623     /* This function is called when the embedded video window is destroyed,
624      * or in the rare case that the embedded window is still here but the
625      * Qt4 interface exits. */
626     assert( videoWidget );
627     videoWidget->release();
628     setVideoOnTop( false );
629     setVideoFullScreen( false );
630
631     if( stackCentralW->currentWidget() == videoWidget )
632         restoreStackOldWidget();
633
634     /* We don't want to have a blank video to popup */
635     stackCentralOldWidget = bgWidget;
636 }
637
638 void MainInterface::setVideoSize( unsigned int w, unsigned int h )
639 {
640     if( !isFullScreen() && !isMaximized() )
641         videoWidget->SetSizing( w, h );
642 }
643
644 void MainInterface::setVideoFullScreen( bool fs )
645 {
646     b_videoFullScreen = fs;
647     if( fs )
648     {
649         int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
650         /* if user hasn't defined screennumber, or screennumber that is bigger
651          * than current number of screens, take screennumber where current interface
652          * is
653          */
654         if( numscreen == -1 || numscreen > QApplication::desktop()->numScreens() )
655             numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
656
657         QRect screenres = QApplication::desktop()->screenGeometry( numscreen );
658
659         /* To be sure window is on proper-screen in xinerama */
660         if( !screenres.contains( pos() ) )
661         {
662             msg_Dbg( p_intf, "Moving video to correct screen");
663             move( QPoint( screenres.x(), screenres.y() ) );
664         }
665         setMinimalView( true );
666         setInterfaceFullScreen( true );
667     }
668     else
669     {
670         /* TODO do we want to restore screen and position ? (when
671          * qt-fullscreen-screennumber is forced) */
672         setMinimalView( b_minimalView );
673         setInterfaceFullScreen( b_interfaceFullScreen );
674     }
675     videoWidget->sync();
676 }
677
678 /* Slot to change the video always-on-top flag.
679  * Emit askVideoOnTop() to invoke this from other thread. */
680 void MainInterface::setVideoOnTop( bool on_top )
681 {
682     Qt::WindowFlags oldflags = windowFlags(), newflags;
683
684     if( on_top )
685         newflags = oldflags | Qt::WindowStaysOnTopHint;
686     else
687         newflags = oldflags & ~Qt::WindowStaysOnTopHint;
688     if( newflags != oldflags && !b_videoFullScreen )
689
690     {
691         setWindowFlags( newflags );
692         show(); /* necessary to apply window flags */
693     }
694 }
695
696 /* Asynchronous call from WindowControl function */
697 int MainInterface::controlVideo( int i_query, va_list args )
698 {
699     switch( i_query )
700     {
701     case VOUT_WINDOW_SET_SIZE:
702     {
703         unsigned int i_width  = va_arg( args, unsigned int );
704         unsigned int i_height = va_arg( args, unsigned int );
705
706         emit askVideoToResize( i_width, i_height );
707         return VLC_SUCCESS;
708     }
709     case VOUT_WINDOW_SET_STATE:
710     {
711         unsigned i_arg = va_arg( args, unsigned );
712         unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
713
714         emit askVideoOnTop( on_top != 0 );
715         return VLC_SUCCESS;
716     }
717     case VOUT_WINDOW_SET_FULLSCREEN:
718     {
719         bool b_fs = va_arg( args, int );
720
721         emit askVideoSetFullScreen( b_fs );
722         return VLC_SUCCESS;
723     }
724     default:
725         msg_Warn( p_intf, "unsupported control query" );
726         return VLC_EGENERIC;
727     }
728 }
729
730 /*****************************************************************************
731  * Playlist, Visualisation and Menus handling
732  *****************************************************************************/
733 /**
734  * Toggle the playlist widget or dialog
735  **/
736 void MainInterface::createPlaylist()
737 {
738     playlistWidget = new PlaylistWidget( p_intf, this );
739
740     if( b_plDocked )
741     {
742         stackCentralW->addWidget( playlistWidget );
743         stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 600, 300 ) ).toSize();
744     }
745     else
746     {
747 #ifdef WIN32
748         playlistWidget->setParent( NULL );
749 #endif
750         playlistWidget->setWindowFlags( Qt::Window );
751
752         /* This will restore the geometry but will not work for position,
753            because of parenting */
754         QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
755                 playlistWidget, QSize( 600, 300 ) );
756     }
757 }
758
759 void MainInterface::togglePlaylist()
760 {
761     if( !playlistWidget )
762     {
763         createPlaylist();
764     }
765
766     if( b_plDocked )
767     {
768         /* Playlist is not visible, show it */
769         if( stackCentralW->currentWidget() != playlistWidget )
770         {
771             showTab( playlistWidget );
772         }
773         else /* Hide it! */
774         {
775             restoreStackOldWidget();
776         }
777         playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
778     }
779     else
780     {
781 #ifdef WIN32
782         playlistWidget->setParent( NULL );
783 #endif
784         playlistWidget->setWindowFlags( Qt::Window );
785         playlistVisible = !playlistVisible;
786         playlistWidget->setVisible( playlistVisible );
787     }
788     debug();
789 }
790
791 void MainInterface::dockPlaylist( bool p_docked )
792 {
793     if( b_plDocked == p_docked ) return;
794     b_plDocked = p_docked;
795
796     if( !playlistWidget ) return; /* Playlist wasn't created yet */
797     if( !p_docked )
798     {
799         stackCentralW->removeWidget( playlistWidget );
800 #ifdef WIN32
801         playlistWidget->setParent( NULL );
802 #endif
803         playlistWidget->setWindowFlags( Qt::Window );
804         QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
805                 playlistWidget, QSize( 600, 300 ) );
806         playlistWidget->show();
807         restoreStackOldWidget();
808     }
809     else
810     {
811         QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
812         playlistWidget->setWindowFlags( Qt::Widget ); // Probably a Qt bug here
813         // It would be logical that QStackWidget::addWidget reset the flags...
814         stackCentralW->addWidget( playlistWidget );
815         showTab( playlistWidget );
816     }
817     playlistVisible = true;
818 }
819
820 /*
821  * setMinimalView is the private function used by
822  * the SLOT toggleMinimalView and setVideoFullScreen
823  */
824 void MainInterface::setMinimalView( bool b_minimal )
825 {
826     menuBar()->setVisible( !b_minimal );
827     controls->setVisible( !b_minimal );
828     statusBar()->setVisible( !b_minimal && b_statusbarVisible );
829     inputC->setVisible( !b_minimal );
830 }
831
832 /*
833  * This public SLOT is used for moving to minimal View Mode
834  *
835  * If b_minimal is false, then we are normalView
836  */
837 void MainInterface::toggleMinimalView( bool b_minimal )
838 {
839     if( !b_minimalView && b_autoresize ) /* Normal mode */
840     {
841         if( stackCentralW->currentWidget() == bgWidget )
842         {
843             if( stackCentralW->height() < 16 )
844             {
845                 resizeStack( stackCentralW->width(), 100 );
846             }
847         }
848     }
849     b_minimalView = b_minimal;
850     if( !b_videoFullScreen )
851     {
852         setMinimalView( b_minimalView );
853         computeMinimumSize();
854     }
855
856     emit minimalViewToggled( b_minimalView );
857 }
858
859 /* toggling advanced controls buttons */
860 void MainInterface::toggleAdvancedButtons()
861 {
862     controls->toggleAdvanced();
863 //    if( fullscreenControls ) fullscreenControls->toggleAdvanced();
864 }
865
866 /* Get the visibility status of the controls (hidden or not, advanced or not) */
867 int MainInterface::getControlsVisibilityStatus()
868 {
869     if( !controls ) return 0;
870     return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
871                 + CONTROLS_ADVANCED * controls->b_advancedVisible );
872 }
873
874 void MainInterface::setStatusBarVisibility( bool b_visible )
875 {
876     statusBar()->setVisible( b_visible );
877     b_statusbarVisible = b_visible;
878     if( controls ) controls->setGripVisible( !b_statusbarVisible );
879 }
880
881 #if 0
882 void MainInterface::visual()
883 {
884     if( !VISIBLE( visualSelector) )
885     {
886         visualSelector->show();
887         if( !THEMIM->getIM()->hasVideo() )
888         {
889             /* Show the background widget */
890         }
891         visualSelectorEnabled = true;
892     }
893     else
894     {
895         /* Stop any currently running visualization */
896         visualSelector->hide();
897         visualSelectorEnabled = false;
898     }
899 }
900 #endif
901
902 /************************************************************************
903  * Other stuff
904  ************************************************************************/
905 void MainInterface::setName( const QString& name )
906 {
907     input_name = name; /* store it for the QSystray use */
908     /* Display it in the status bar, but also as a Tooltip in case it doesn't
909        fit in the label */
910     nameLabel->setText( name );
911     nameLabel->setToolTip( name );
912 }
913
914 /**
915  * Give the decorations of the Main Window a correct Name.
916  * If nothing is given, set it to VLC...
917  **/
918 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
919 {
920     if( aTitle.isEmpty() )
921     {
922         setWindowTitle( qtr( "VLC media player" ) );
923     }
924     else
925     {
926         setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
927     }
928 }
929
930 void MainInterface::showCryptedLabel( bool b_show )
931 {
932     if( cryptedLabel == NULL )
933     {
934         cryptedLabel = new QLabel;
935         // The lock icon is not the right one for DRM protection/scrambled.
936         //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
937         cryptedLabel->setText( "DRM" );
938         statusBar()->addWidget( cryptedLabel );
939     }
940
941     cryptedLabel->setVisible( b_show );
942 }
943
944 void MainInterface::showBuffering( float f_cache )
945 {
946     QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
947     statusBar()->showMessage( amount, 1000 );
948 }
949
950 /*****************************************************************************
951  * Systray Icon and Systray Menu
952  *****************************************************************************/
953 #ifndef HAVE_MAEMO
954 /**
955  * Create a SystemTray icon and a menu that would go with it.
956  * Connects to a click handler on the icon.
957  **/
958 void MainInterface::createSystray()
959 {
960     QIcon iconVLC;
961     if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
962         iconVLC =  QIcon( ":/logo/vlc128-xmas.png" );
963     else
964         iconVLC =  QIcon( ":/logo/vlc128.png" );
965     sysTray = new QSystemTrayIcon( iconVLC, this );
966     sysTray->setToolTip( qtr( "VLC media player" ));
967
968     systrayMenu = new QMenu( qtr( "VLC media player" ), this );
969     systrayMenu->setIcon( iconVLC );
970
971     QVLCMenu::updateSystrayMenu( this, p_intf, true );
972     sysTray->show();
973
974     CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
975              this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
976 }
977
978 /**
979  * Updates the Systray Icon's menu and toggle the main interface
980  */
981 void MainInterface::toggleUpdateSystrayMenu()
982 {
983     /* If hidden, show it */
984     if( isHidden() )
985     {
986         show();
987         activateWindow();
988     }
989     else if( isMinimized() )
990     {
991         /* Minimized */
992         showNormal();
993         activateWindow();
994     }
995     else
996     {
997         /* Visible (possibly under other windows) */
998 #ifdef WIN32
999         /* check if any visible window is above vlc in the z-order,
1000          * but ignore the ones always on top
1001          * and the ones which can't be activated */
1002         WINDOWINFO wi;
1003         HWND hwnd;
1004         wi.cbSize = sizeof( WINDOWINFO );
1005         for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
1006                 hwnd && ( !IsWindowVisible( hwnd ) ||
1007                     ( GetWindowInfo( hwnd, &wi ) &&
1008                       (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
1009                 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
1010             if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
1011                 (wi.dwExStyle&WS_EX_TOPMOST) )
1012             {
1013                 hide();
1014             }
1015             else
1016             {
1017                 activateWindow();
1018             }
1019 #else
1020         hide();
1021 #endif
1022     }
1023     QVLCMenu::updateSystrayMenu( this, p_intf );
1024 }
1025
1026 void MainInterface::showUpdateSystrayMenu()
1027 {
1028     if( isHidden() )
1029         show();
1030     if( isMinimized() )
1031         showNormal();
1032     activateWindow();
1033
1034     QVLCMenu::updateSystrayMenu( this, p_intf );
1035 }
1036
1037 void MainInterface::hideUpdateSystrayMenu()
1038 {
1039     hide();
1040     QVLCMenu::updateSystrayMenu( this, p_intf );
1041 }
1042
1043 void MainInterface::handleSystrayClick(
1044                                     QSystemTrayIcon::ActivationReason reason )
1045 {
1046     switch( reason )
1047     {
1048         case QSystemTrayIcon::Trigger:
1049         case QSystemTrayIcon::DoubleClick:
1050 #ifdef Q_WS_MAC
1051             QVLCMenu::updateSystrayMenu( this, p_intf );
1052 #else
1053             toggleUpdateSystrayMenu();
1054 #endif
1055             break;
1056         case QSystemTrayIcon::MiddleClick:
1057             sysTray->showMessage( qtr( "VLC media player" ),
1058                     qtr( "Control menu for the player" ),
1059                     QSystemTrayIcon::Information, 3000 );
1060             break;
1061         default:
1062             break;
1063     }
1064 }
1065
1066 /**
1067  * Updates the name of the systray Icon tooltip.
1068  * Doesn't check if the systray exists, check before you call it.
1069  **/
1070 void MainInterface::updateSystrayTooltipName( const QString& name )
1071 {
1072     if( name.isEmpty() )
1073     {
1074         sysTray->setToolTip( qtr( "VLC media player" ) );
1075     }
1076     else
1077     {
1078         sysTray->setToolTip( name );
1079         if( b_notificationEnabled && ( isHidden() || isMinimized() ) )
1080         {
1081             sysTray->showMessage( qtr( "VLC media player" ), name,
1082                     QSystemTrayIcon::NoIcon, 3000 );
1083         }
1084     }
1085
1086     QVLCMenu::updateSystrayMenu( this, p_intf );
1087 }
1088
1089 /**
1090  * Updates the status of the systray Icon tooltip.
1091  * Doesn't check if the systray exists, check before you call it.
1092  **/
1093 void MainInterface::updateSystrayTooltipStatus( int i_status )
1094 {
1095     switch( i_status )
1096     {
1097     case PLAYING_S:
1098         sysTray->setToolTip( input_name );
1099         break;
1100     case PAUSE_S:
1101         sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1102         break;
1103     default:
1104         sysTray->setToolTip( qtr( "VLC media player" ) );
1105         break;
1106     }
1107     QVLCMenu::updateSystrayMenu( this, p_intf );
1108 }
1109 #endif
1110
1111 void MainInterface::changeEvent(QEvent *event)
1112 {
1113     if( event->type() == QEvent::WindowStateChange )
1114     {
1115         QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
1116         Qt::WindowStates newState = windowState();
1117         Qt::WindowStates oldState = windowStateChangeEvent->oldState();
1118
1119         if( newState & Qt::WindowMinimized )
1120         {
1121             b_hasPausedWhenMinimized = false;
1122
1123             if( THEMIM->getIM()->playingStatus() == PLAYING_S &&
1124                 THEMIM->getIM()->hasVideo() &&
1125                 !THEMIM->getIM()->hasVisualisation() &&
1126                 var_InheritBool( p_intf, "qt-pause-minimized" ) )
1127             {
1128                 b_hasPausedWhenMinimized = true;
1129                 THEMIM->pause();
1130             }
1131         }
1132         else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
1133         {
1134             if( b_hasPausedWhenMinimized )
1135             {
1136                 THEMIM->play();
1137             }
1138         }
1139     }
1140
1141     QWidget::changeEvent(event);
1142 }
1143
1144 /************************************************************************
1145  * D&D Events
1146  ************************************************************************/
1147 void MainInterface::dropEvent(QDropEvent *event)
1148 {
1149     dropEventPlay( event, true );
1150 }
1151
1152 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play )
1153 {
1154     if( event->possibleActions() & Qt::CopyAction )
1155        event->setDropAction( Qt::CopyAction );
1156     else
1157         return;
1158
1159     const QMimeData *mimeData = event->mimeData();
1160
1161     /* D&D of a subtitles file, add it on the fly */
1162     if( mimeData->urls().size() == 1 && THEMIM->getIM()->hasInput() )
1163     {
1164         if( !input_AddSubtitle( THEMIM->getInput(),
1165                  qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1166                  true ) )
1167         {
1168             event->accept();
1169             return;
1170         }
1171     }
1172
1173     bool first = b_play;
1174     foreach( const QUrl &url, mimeData->urls() )
1175     {
1176         if( url.isValid() )
1177         {
1178             QString mrl = toURI( url.toEncoded().constData() );
1179             playlist_Add( THEPL, qtu(mrl), NULL,
1180                           PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1181                           PLAYLIST_END, true, pl_Unlocked );
1182             first = false;
1183             RecentsMRL::getInstance( p_intf )->addRecent( url.toString() );
1184         }
1185     }
1186
1187     /* Browsers give content as text if you dnd the addressbar,
1188        so check if mimedata has valid url in text and use it
1189        if we didn't get any normal Urls()*/
1190     if( !mimeData->hasUrls() && mimeData->hasText() &&
1191         QUrl(mimeData->text()).isValid() )
1192     {
1193         QString mrl = toURI( mimeData->text() );
1194         playlist_Add( THEPL, qtu(mrl), NULL,
1195                       PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1196                       PLAYLIST_END, true, pl_Unlocked );
1197     }
1198     event->accept();
1199 }
1200 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1201 {
1202      event->acceptProposedAction();
1203 }
1204 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1205 {
1206      event->acceptProposedAction();
1207 }
1208 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1209 {
1210      event->accept();
1211 }
1212
1213 /************************************************************************
1214  * Events stuff
1215  ************************************************************************/
1216 void MainInterface::keyPressEvent( QKeyEvent *e )
1217 {
1218     handleKeyPress( e );
1219 }
1220
1221 void MainInterface::handleKeyPress( QKeyEvent *e )
1222 {
1223     if( ( e->modifiers() &  Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) )
1224     {
1225         toggleMinimalView( !b_minimalView );
1226         e->accept();
1227     }
1228
1229     int i_vlck = qtEventToVLCKey( e );
1230     if( i_vlck > 0 )
1231     {
1232         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1233         e->accept();
1234     }
1235     else
1236         e->ignore();
1237 }
1238
1239 void MainInterface::wheelEvent( QWheelEvent *e )
1240 {
1241     int i_vlckey = qtWheelEventToVLCKey( e );
1242     var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1243     e->accept();
1244 }
1245
1246 void MainInterface::closeEvent( QCloseEvent *e )
1247 {
1248     e->ignore();      /* Do not quit */
1249 //  hide();
1250     emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
1251 }
1252
1253 void MainInterface::setInterfaceFullScreen( bool fs )
1254 {
1255     if( fs )
1256         setWindowState( windowState() | Qt::WindowFullScreen );
1257     else
1258         setWindowState( windowState() & ~Qt::WindowFullScreen );
1259 }
1260 void MainInterface::toggleInterfaceFullScreen()
1261 {
1262     b_interfaceFullScreen = !b_interfaceFullScreen;
1263     if( !b_videoFullScreen )
1264         setInterfaceFullScreen( b_interfaceFullScreen );
1265     emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1266 }
1267
1268 /*****************************************************************************
1269  * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1270  *  We don't show the menu directly here because we don't want the
1271  *  caller to block for a too long time.
1272  *****************************************************************************/
1273 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1274                         vlc_value_t old_val, vlc_value_t new_val, void *param )
1275 {
1276     VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1277
1278     intf_thread_t *p_intf = (intf_thread_t *)param;
1279
1280     if( p_intf->pf_show_dialog )
1281     {
1282         p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1283                                 new_val.b_bool, NULL );
1284     }
1285
1286     return VLC_SUCCESS;
1287 }
1288
1289 /*****************************************************************************
1290  * IntfShowCB: callback triggered by the intf-show libvlc variable.
1291  *****************************************************************************/
1292 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1293                        vlc_value_t old_val, vlc_value_t new_val, void *param )
1294 {
1295     VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1296     VLC_UNUSED( new_val );
1297
1298     intf_thread_t *p_intf = (intf_thread_t *)param;
1299     p_intf->p_sys->p_mi->toggleFSC();
1300
1301     /* Show event */
1302      return VLC_SUCCESS;
1303 }