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