]> git.sesse.net Git - vlc/blob - modules/gui/qt4/main_interface.cpp
Qt: simplify
[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     /* Request the videoWidget */
596     WId ret = videoWidget->request( pi_x, pi_y,
597                                     pi_width, pi_height, !b_autoresize );
598     *p_id = ret;
599     if( ret ) /* The videoWidget is available */
600     {
601         /* Consider the video active now */
602         showVideo();
603
604         /* Ask videoWidget to resize correctly, if we are in normal mode */
605         if( !isFullScreen() && !isMaximized() && b_autoresize )
606             videoWidget->SetSizing( *pi_width, *pi_height );
607     }
608 }
609
610 /* Asynchronous call from the WindowClose function */
611 void MainInterface::releaseVideo( void )
612 {
613     emit askReleaseVideo();
614 }
615
616 /* Function that is CONNECTED to the previous emit */
617 void MainInterface::releaseVideoSlot( void )
618 {
619     /* This function is called when the embedded video window is destroyed,
620      * or in the rare case that the embedded window is still here but the
621      * Qt4 interface exits. */
622     assert( videoWidget );
623     videoWidget->release();
624     setVideoOnTop( false );
625     setVideoFullScreen( false );
626
627     if( stackCentralW->currentWidget() == videoWidget )
628         restoreStackOldWidget();
629
630     /* We don't want to have a blank video to popup */
631     stackCentralOldWidget = bgWidget;
632 }
633
634 void MainInterface::setVideoSize( unsigned int w, unsigned int h )
635 {
636     if( !isFullScreen() && !isMaximized() )
637         videoWidget->SetSizing( w, h );
638 }
639
640 void MainInterface::setVideoFullScreen( bool fs )
641 {
642     b_videoFullScreen = fs;
643     if( fs )
644     {
645         int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
646         /* if user hasn't defined screennumber, or screennumber that is bigger
647          * than current number of screens, take screennumber where current interface
648          * is
649          */
650         if( numscreen == -1 || numscreen > QApplication::desktop()->numScreens() )
651             numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
652
653         QRect screenres = QApplication::desktop()->screenGeometry( numscreen );
654
655         /* To be sure window is on proper-screen in xinerama */
656         if( !screenres.contains( pos() ) )
657         {
658             msg_Dbg( p_intf, "Moving video to correct screen");
659             move( QPoint( screenres.x(), screenres.y() ) );
660         }
661         setMinimalView( true );
662         setInterfaceFullScreen( true );
663     }
664     else
665     {
666         /* TODO do we want to restore screen and position ? (when
667          * qt-fullscreen-screennumber is forced) */
668         setMinimalView( b_minimalView );
669         setInterfaceFullScreen( b_interfaceFullScreen );
670     }
671     videoWidget->sync();
672 }
673
674 /* Slot to change the video always-on-top flag.
675  * Emit askVideoOnTop() to invoke this from other thread. */
676 void MainInterface::setVideoOnTop( bool on_top )
677 {
678     Qt::WindowFlags oldflags = windowFlags(), newflags;
679
680     if( on_top )
681         newflags = oldflags | Qt::WindowStaysOnTopHint;
682     else
683         newflags = oldflags & ~Qt::WindowStaysOnTopHint;
684     if( newflags != oldflags && !b_videoFullScreen )
685
686     {
687         setWindowFlags( newflags );
688         show(); /* necessary to apply window flags */
689     }
690 }
691
692 /* Asynchronous call from WindowControl function */
693 int MainInterface::controlVideo( int i_query, va_list args )
694 {
695     switch( i_query )
696     {
697     case VOUT_WINDOW_SET_SIZE:
698     {
699         unsigned int i_width  = va_arg( args, unsigned int );
700         unsigned int i_height = va_arg( args, unsigned int );
701
702         emit askVideoToResize( i_width, i_height );
703         return VLC_SUCCESS;
704     }
705     case VOUT_WINDOW_SET_STATE:
706     {
707         unsigned i_arg = va_arg( args, unsigned );
708         unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
709
710         emit askVideoOnTop( on_top != 0 );
711         return VLC_SUCCESS;
712     }
713     case VOUT_WINDOW_SET_FULLSCREEN:
714     {
715         bool b_fs = va_arg( args, int );
716
717         emit askVideoSetFullScreen( b_fs );
718         return VLC_SUCCESS;
719     }
720     default:
721         msg_Warn( p_intf, "unsupported control query" );
722         return VLC_EGENERIC;
723     }
724 }
725
726 /*****************************************************************************
727  * Playlist, Visualisation and Menus handling
728  *****************************************************************************/
729 /**
730  * Toggle the playlist widget or dialog
731  **/
732 void MainInterface::createPlaylist()
733 {
734     playlistWidget = new PlaylistWidget( p_intf, this );
735
736     if( b_plDocked )
737     {
738         stackCentralW->addWidget( playlistWidget );
739         stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 600, 300 ) ).toSize();
740     }
741     else
742     {
743 #ifdef WIN32
744         playlistWidget->setParent( NULL );
745 #endif
746         playlistWidget->setWindowFlags( Qt::Window );
747
748         /* This will restore the geometry but will not work for position,
749            because of parenting */
750         QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
751                 playlistWidget, QSize( 600, 300 ) );
752     }
753 }
754
755 void MainInterface::togglePlaylist()
756 {
757     if( !playlistWidget )
758     {
759         createPlaylist();
760     }
761
762     if( b_plDocked )
763     {
764         /* Playlist is not visible, show it */
765         if( stackCentralW->currentWidget() != playlistWidget )
766         {
767             showTab( playlistWidget );
768         }
769         else /* Hide it! */
770         {
771             restoreStackOldWidget();
772         }
773         playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
774     }
775     else
776     {
777 #ifdef WIN32
778         playlistWidget->setParent( NULL );
779 #endif
780         playlistWidget->setWindowFlags( Qt::Window );
781         playlistVisible = !playlistVisible;
782         playlistWidget->setVisible( playlistVisible );
783     }
784     debug();
785 }
786
787 void MainInterface::dockPlaylist( bool p_docked )
788 {
789     if( b_plDocked == p_docked ) return;
790     b_plDocked = p_docked;
791
792     if( !playlistWidget ) return; /* Playlist wasn't created yet */
793     if( !p_docked )
794     {
795         stackCentralW->removeWidget( playlistWidget );
796 #ifdef WIN32
797         playlistWidget->setParent( NULL );
798 #endif
799         playlistWidget->setWindowFlags( Qt::Window );
800         QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
801                 playlistWidget, QSize( 600, 300 ) );
802         playlistWidget->show();
803         restoreStackOldWidget();
804     }
805     else
806     {
807         QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
808         playlistWidget->setWindowFlags( Qt::Widget ); // Probably a Qt bug here
809         // It would be logical that QStackWidget::addWidget reset the flags...
810         stackCentralW->addWidget( playlistWidget );
811         showTab( playlistWidget );
812     }
813     playlistVisible = true;
814 }
815
816 /*
817  * setMinimalView is the private function used by
818  * the SLOT toggleMinimalView and setVideoFullScreen
819  */
820 void MainInterface::setMinimalView( bool b_minimal )
821 {
822     menuBar()->setVisible( !b_minimal );
823     controls->setVisible( !b_minimal );
824     statusBar()->setVisible( !b_minimal && b_statusbarVisible );
825     inputC->setVisible( !b_minimal );
826 }
827
828 /*
829  * This public SLOT is used for moving to minimal View Mode
830  *
831  * If b_minimal is false, then we are normalView
832  */
833 void MainInterface::toggleMinimalView( bool b_minimal )
834 {
835     if( !b_minimalView && b_autoresize ) /* Normal mode */
836     {
837         if( stackCentralW->currentWidget() == bgWidget )
838         {
839             if( stackCentralW->height() < 16 )
840             {
841                 resizeStack( stackCentralW->width(), 100 );
842             }
843         }
844     }
845     b_minimalView = b_minimal;
846     if( !b_videoFullScreen )
847     {
848         setMinimalView( b_minimalView );
849         computeMinimumSize();
850     }
851
852     emit minimalViewToggled( b_minimalView );
853 }
854
855 /* toggling advanced controls buttons */
856 void MainInterface::toggleAdvancedButtons()
857 {
858     controls->toggleAdvanced();
859 //    if( fullscreenControls ) fullscreenControls->toggleAdvanced();
860 }
861
862 /* Get the visibility status of the controls (hidden or not, advanced or not) */
863 int MainInterface::getControlsVisibilityStatus()
864 {
865     if( !controls ) return 0;
866     return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
867                 + CONTROLS_ADVANCED * controls->b_advancedVisible );
868 }
869
870 void MainInterface::setStatusBarVisibility( bool b_visible )
871 {
872     statusBar()->setVisible( b_visible );
873     b_statusbarVisible = b_visible;
874     if( controls ) controls->setGripVisible( !b_statusbarVisible );
875 }
876
877 #if 0
878 void MainInterface::visual()
879 {
880     if( !VISIBLE( visualSelector) )
881     {
882         visualSelector->show();
883         if( !THEMIM->getIM()->hasVideo() )
884         {
885             /* Show the background widget */
886         }
887         visualSelectorEnabled = true;
888     }
889     else
890     {
891         /* Stop any currently running visualization */
892         visualSelector->hide();
893         visualSelectorEnabled = false;
894     }
895 }
896 #endif
897
898 /************************************************************************
899  * Other stuff
900  ************************************************************************/
901 void MainInterface::setName( const QString& name )
902 {
903     input_name = name; /* store it for the QSystray use */
904     /* Display it in the status bar, but also as a Tooltip in case it doesn't
905        fit in the label */
906     nameLabel->setText( name );
907     nameLabel->setToolTip( name );
908 }
909
910 /**
911  * Give the decorations of the Main Window a correct Name.
912  * If nothing is given, set it to VLC...
913  **/
914 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
915 {
916     if( aTitle.isEmpty() )
917     {
918         setWindowTitle( qtr( "VLC media player" ) );
919     }
920     else
921     {
922         setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
923     }
924 }
925
926 void MainInterface::showCryptedLabel( bool b_show )
927 {
928     if( cryptedLabel == NULL )
929     {
930         cryptedLabel = new QLabel;
931         // The lock icon is not the right one for DRM protection/scrambled.
932         //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
933         cryptedLabel->setText( "DRM" );
934         statusBar()->addWidget( cryptedLabel );
935     }
936
937     cryptedLabel->setVisible( b_show );
938 }
939
940 void MainInterface::showBuffering( float f_cache )
941 {
942     QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
943     statusBar()->showMessage( amount, 1000 );
944 }
945
946 /*****************************************************************************
947  * Systray Icon and Systray Menu
948  *****************************************************************************/
949 #ifndef HAVE_MAEMO
950 /**
951  * Create a SystemTray icon and a menu that would go with it.
952  * Connects to a click handler on the icon.
953  **/
954 void MainInterface::createSystray()
955 {
956     QIcon iconVLC;
957     if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
958         iconVLC =  QIcon( ":/logo/vlc128-xmas.png" );
959     else
960         iconVLC =  QIcon( ":/logo/vlc128.png" );
961     sysTray = new QSystemTrayIcon( iconVLC, this );
962     sysTray->setToolTip( qtr( "VLC media player" ));
963
964     systrayMenu = new QMenu( qtr( "VLC media player" ), this );
965     systrayMenu->setIcon( iconVLC );
966
967     QVLCMenu::updateSystrayMenu( this, p_intf, true );
968     sysTray->show();
969
970     CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
971              this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
972 }
973
974 /**
975  * Updates the Systray Icon's menu and toggle the main interface
976  */
977 void MainInterface::toggleUpdateSystrayMenu()
978 {
979     /* If hidden, show it */
980     if( isHidden() )
981     {
982         show();
983         activateWindow();
984     }
985     else if( isMinimized() )
986     {
987         /* Minimized */
988         showNormal();
989         activateWindow();
990     }
991     else
992     {
993         /* Visible (possibly under other windows) */
994 #ifdef WIN32
995         /* check if any visible window is above vlc in the z-order,
996          * but ignore the ones always on top
997          * and the ones which can't be activated */
998         WINDOWINFO wi;
999         HWND hwnd;
1000         wi.cbSize = sizeof( WINDOWINFO );
1001         for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
1002                 hwnd && ( !IsWindowVisible( hwnd ) ||
1003                     ( GetWindowInfo( hwnd, &wi ) &&
1004                       (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
1005                 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
1006             if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
1007                 (wi.dwExStyle&WS_EX_TOPMOST) )
1008             {
1009                 hide();
1010             }
1011             else
1012             {
1013                 activateWindow();
1014             }
1015 #else
1016         hide();
1017 #endif
1018     }
1019     QVLCMenu::updateSystrayMenu( this, p_intf );
1020 }
1021
1022 void MainInterface::showUpdateSystrayMenu()
1023 {
1024     if( isHidden() )
1025         show();
1026     if( isMinimized() )
1027         showNormal();
1028     activateWindow();
1029
1030     QVLCMenu::updateSystrayMenu( this, p_intf );
1031 }
1032
1033 void MainInterface::hideUpdateSystrayMenu()
1034 {
1035     hide();
1036     QVLCMenu::updateSystrayMenu( this, p_intf );
1037 }
1038
1039 void MainInterface::handleSystrayClick(
1040                                     QSystemTrayIcon::ActivationReason reason )
1041 {
1042     switch( reason )
1043     {
1044         case QSystemTrayIcon::Trigger:
1045         case QSystemTrayIcon::DoubleClick:
1046 #ifdef Q_WS_MAC
1047             QVLCMenu::updateSystrayMenu( this, p_intf );
1048 #else
1049             toggleUpdateSystrayMenu();
1050 #endif
1051             break;
1052         case QSystemTrayIcon::MiddleClick:
1053             sysTray->showMessage( qtr( "VLC media player" ),
1054                     qtr( "Control menu for the player" ),
1055                     QSystemTrayIcon::Information, 3000 );
1056             break;
1057         default:
1058             break;
1059     }
1060 }
1061
1062 /**
1063  * Updates the name of the systray Icon tooltip.
1064  * Doesn't check if the systray exists, check before you call it.
1065  **/
1066 void MainInterface::updateSystrayTooltipName( const QString& name )
1067 {
1068     if( name.isEmpty() )
1069     {
1070         sysTray->setToolTip( qtr( "VLC media player" ) );
1071     }
1072     else
1073     {
1074         sysTray->setToolTip( name );
1075         if( b_notificationEnabled && ( isHidden() || isMinimized() ) )
1076         {
1077             sysTray->showMessage( qtr( "VLC media player" ), name,
1078                     QSystemTrayIcon::NoIcon, 3000 );
1079         }
1080     }
1081
1082     QVLCMenu::updateSystrayMenu( this, p_intf );
1083 }
1084
1085 /**
1086  * Updates the status of the systray Icon tooltip.
1087  * Doesn't check if the systray exists, check before you call it.
1088  **/
1089 void MainInterface::updateSystrayTooltipStatus( int i_status )
1090 {
1091     switch( i_status )
1092     {
1093     case PLAYING_S:
1094         sysTray->setToolTip( input_name );
1095         break;
1096     case PAUSE_S:
1097         sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1098         break;
1099     default:
1100         sysTray->setToolTip( qtr( "VLC media player" ) );
1101         break;
1102     }
1103     QVLCMenu::updateSystrayMenu( this, p_intf );
1104 }
1105 #endif
1106
1107 void MainInterface::changeEvent(QEvent *event)
1108 {
1109     if( event->type() == QEvent::WindowStateChange )
1110     {
1111         QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
1112         Qt::WindowStates newState = windowState();
1113         Qt::WindowStates oldState = windowStateChangeEvent->oldState();
1114
1115         if( newState & Qt::WindowMinimized )
1116         {
1117             b_hasPausedWhenMinimized = false;
1118
1119             if( THEMIM->getIM()->playingStatus() == PLAYING_S &&
1120                 THEMIM->getIM()->hasVideo() &&
1121                 !THEMIM->getIM()->hasVisualisation() &&
1122                 var_InheritBool( p_intf, "qt-pause-minimized" ) )
1123             {
1124                 b_hasPausedWhenMinimized = true;
1125                 THEMIM->pause();
1126             }
1127         }
1128         else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
1129         {
1130             if( b_hasPausedWhenMinimized )
1131             {
1132                 THEMIM->play();
1133             }
1134         }
1135     }
1136
1137     QWidget::changeEvent(event);
1138 }
1139
1140 /************************************************************************
1141  * D&D Events
1142  ************************************************************************/
1143 void MainInterface::dropEvent(QDropEvent *event)
1144 {
1145     dropEventPlay( event, true );
1146 }
1147
1148 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play )
1149 {
1150     if( event->possibleActions() & Qt::CopyAction )
1151        event->setDropAction( Qt::CopyAction );
1152     else
1153         return;
1154
1155     const QMimeData *mimeData = event->mimeData();
1156
1157     /* D&D of a subtitles file, add it on the fly */
1158     if( mimeData->urls().size() == 1 && THEMIM->getIM()->hasInput() )
1159     {
1160         if( !input_AddSubtitle( THEMIM->getInput(),
1161                  qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1162                  true ) )
1163         {
1164             event->accept();
1165             return;
1166         }
1167     }
1168
1169     bool first = b_play;
1170     foreach( const QUrl &url, mimeData->urls() )
1171     {
1172         if( url.isValid() )
1173         {
1174             QString mrl = toURI( url.toEncoded().constData() );
1175             playlist_Add( THEPL, qtu(mrl), NULL,
1176                           PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1177                           PLAYLIST_END, true, pl_Unlocked );
1178             first = false;
1179             RecentsMRL::getInstance( p_intf )->addRecent( url.toString() );
1180         }
1181     }
1182
1183     /* Browsers give content as text if you dnd the addressbar,
1184        so check if mimedata has valid url in text and use it
1185        if we didn't get any normal Urls()*/
1186     if( !mimeData->hasUrls() && mimeData->hasText() &&
1187         QUrl(mimeData->text()).isValid() )
1188     {
1189         QString mrl = toURI( mimeData->text() );
1190         playlist_Add( THEPL, qtu(mrl), NULL,
1191                       PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1192                       PLAYLIST_END, true, pl_Unlocked );
1193     }
1194     event->accept();
1195 }
1196 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1197 {
1198      event->acceptProposedAction();
1199 }
1200 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1201 {
1202      event->acceptProposedAction();
1203 }
1204 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1205 {
1206      event->accept();
1207 }
1208
1209 /************************************************************************
1210  * Events stuff
1211  ************************************************************************/
1212 void MainInterface::keyPressEvent( QKeyEvent *e )
1213 {
1214     handleKeyPress( e );
1215 }
1216
1217 void MainInterface::handleKeyPress( QKeyEvent *e )
1218 {
1219     if( ( e->modifiers() &  Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) )
1220     {
1221         toggleMinimalView( !b_minimalView );
1222         e->accept();
1223     }
1224
1225     int i_vlck = qtEventToVLCKey( e );
1226     if( i_vlck > 0 )
1227     {
1228         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1229         e->accept();
1230     }
1231     else
1232         e->ignore();
1233 }
1234
1235 void MainInterface::wheelEvent( QWheelEvent *e )
1236 {
1237     int i_vlckey = qtWheelEventToVLCKey( e );
1238     var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1239     e->accept();
1240 }
1241
1242 void MainInterface::closeEvent( QCloseEvent *e )
1243 {
1244     e->ignore();      /* Do not quit */
1245 //  hide();
1246     emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
1247 }
1248
1249 void MainInterface::setInterfaceFullScreen( bool fs )
1250 {
1251     if( fs )
1252         setWindowState( windowState() | Qt::WindowFullScreen );
1253     else
1254         setWindowState( windowState() & ~Qt::WindowFullScreen );
1255 }
1256 void MainInterface::toggleInterfaceFullScreen()
1257 {
1258     b_interfaceFullScreen = !b_interfaceFullScreen;
1259     if( !b_videoFullScreen )
1260         setInterfaceFullScreen( b_interfaceFullScreen );
1261     emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1262 }
1263
1264 /*****************************************************************************
1265  * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1266  *  We don't show the menu directly here because we don't want the
1267  *  caller to block for a too long time.
1268  *****************************************************************************/
1269 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1270                         vlc_value_t old_val, vlc_value_t new_val, void *param )
1271 {
1272     VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1273
1274     intf_thread_t *p_intf = (intf_thread_t *)param;
1275
1276     if( p_intf->pf_show_dialog )
1277     {
1278         p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1279                                 new_val.b_bool, NULL );
1280     }
1281
1282     return VLC_SUCCESS;
1283 }
1284
1285 /*****************************************************************************
1286  * IntfShowCB: callback triggered by the intf-show libvlc variable.
1287  *****************************************************************************/
1288 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1289                        vlc_value_t old_val, vlc_value_t new_val, void *param )
1290 {
1291     VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1292     VLC_UNUSED( new_val );
1293
1294     intf_thread_t *p_intf = (intf_thread_t *)param;
1295     p_intf->p_sys->p_mi->toggleFSC();
1296
1297     /* Show event */
1298      return VLC_SUCCESS;
1299 }