]> git.sesse.net Git - vlc/blob - modules/gui/qt4/main_interface.cpp
9fd996cd0d913913cdcfc374d083ac452a34030c
[vlc] / modules / gui / qt4 / main_interface.cpp
1 /*****************************************************************************
2  * main_interface.cpp : Main interface
3  ****************************************************************************
4  * Copyright (C) 2006-2011 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
36 #include "util/customwidgets.hpp"               // qtEventToVLCKey, QVLCStackedWidget
37 #include "util/qt_dirs.hpp"                     // toNativeSeparators
38
39 #include "components/interface_widgets.hpp"     // bgWidget, videoWidget
40 #include "components/controller.hpp"            // controllers
41 #include "components/playlist/playlist.hpp"     // plWidget
42 #include "dialogs/firstrun.hpp"                 // First Run
43 #include "dialogs/playlist.hpp"                 // PlaylistDialog
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 #include <QMimeData>
55
56 #include <QMenu>
57 #include <QMenuBar>
58 #include <QStatusBar>
59 #include <QLabel>
60 #include <QStackedWidget>
61 #include <QFileInfo>
62
63 #include <QTimer>
64
65 #include <vlc_keys.h>                       /* Wheel event */
66 #include <vlc_vout_display.h>               /* vout_thread_t and VOUT_ events */
67
68
69 #if defined(_WIN32) && HAS_QT5
70 #include <QWindow>
71 #include <qpa/qplatformnativeinterface.h>
72 #endif
73
74 // #define DEBUG_INTF
75
76 /* Callback prototypes */
77 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
78                         vlc_value_t old_val, vlc_value_t new_val, void *param );
79 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
80                        vlc_value_t old_val, vlc_value_t new_val, void *param );
81 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
82                        vlc_value_t old_val, vlc_value_t new_val, void *param );
83 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
84                            vlc_value_t old_val, vlc_value_t new_val,
85                            void *param );
86
87 const QEvent::Type MainInterface::ToolbarsNeedRebuild =
88         (QEvent::Type)QEvent::registerEventType();
89
90 MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
91 {
92     /* Variables initialisation */
93     bgWidget             = NULL;
94     videoWidget          = NULL;
95     playlistWidget       = NULL;
96     stackCentralOldWidget= NULL;
97     sysTray              = NULL;
98     fullscreenControls   = NULL;
99     cryptedLabel         = NULL;
100     controls             = NULL;
101     inputC               = NULL;
102
103     b_hideAfterCreation  = false; // --qt-start-minimized
104     playlistVisible      = false;
105     input_name           = "";
106     b_interfaceFullScreen= false;
107     b_hasPausedWhenMinimized = false;
108     i_kc_offset          = false;
109
110     /* Ask for Privacy */
111     FirstRun::CheckAndRun( this, p_intf );
112
113     /**
114      *  Configuration and settings
115      *  Pre-building of interface
116      **/
117     /* Main settings */
118     setFocusPolicy( Qt::StrongFocus );
119     setAcceptDrops( true );
120     setWindowRole( "vlc-main" );
121     setWindowIcon( QApplication::windowIcon() );
122     setWindowOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
123 #ifdef Q_OS_MAC
124     setAttribute( Qt::WA_MacBrushedMetal );
125 #endif
126
127     /* Is video in embedded in the UI or not */
128     b_videoEmbedded = var_InheritBool( p_intf, "embedded-video" );
129
130     /* Does the interface resize to video size or the opposite */
131     b_autoresize = var_InheritBool( p_intf, "qt-video-autoresize" );
132
133     /* Are we in the enhanced always-video mode or not ? */
134     b_minimalView = var_InheritBool( p_intf, "qt-minimal-view" );
135
136     /* Do we want anoying popups or not */
137     i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
138
139     /* */
140     b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
141
142     /* Set the other interface settings */
143     settings = getSettings();
144
145 #ifdef _WIN32
146     /* Volume keys */
147     p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
148 #endif
149
150     /* */
151     b_plDocked = getSettings()->value( "MainWindow/pl-dock-status", true ).toBool();
152
153
154     /**************************
155      *  UI and Widgets design
156      **************************/
157     setVLCWindowsTitle();
158
159     /************
160      * Menu Bar *
161      ************/
162     VLCMenuBar::createMenuBar( this, p_intf );
163     CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
164              THEDP, destroyPopupMenu() );
165
166     createMainWidget( settings );
167
168     /**************
169      * Status Bar *
170      **************/
171     createStatusBar();
172     setStatusBarVisibility( getSettings()->value( "MainWindow/status-bar-visible", false ).toBool() );
173
174 #ifdef _WIN32
175     himl = NULL;
176     p_taskbl = NULL;
177     taskbar_wmsg = RegisterWindowMessage(TEXT("TaskbarButtonCreated"));
178 #endif
179
180     /*********************************
181      * Create the Systray Management *
182      *********************************/
183     initSystray();
184
185     /*************************************************************
186      * Connect the input manager to the GUI elements it manages  *
187      * Beware initSystray did some connects on input manager too *
188      *************************************************************/
189     /**
190      * Connects on nameChanged()
191      * Those connects are different because options can impeach them to trigger.
192      **/
193     /* Main Interface statusbar */
194     CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
195              this, setName( const QString& ) );
196     /* and title of the Main Interface*/
197     if( var_InheritBool( p_intf, "qt-name-in-title" ) )
198     {
199         CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
200                  this, setVLCWindowsTitle( const QString& ) );
201     }
202     /* END CONNECTS ON IM */
203
204     /* VideoWidget connects for asynchronous calls */
205     b_videoFullScreen = false;
206     connect( this, SIGNAL(askGetVideo(WId*,struct vout_window_t*,unsigned*,unsigned *)),
207              this, SLOT(getVideoSlot(WId*,struct vout_window_t*,unsigned*,unsigned*)),
208              Qt::BlockingQueuedConnection );
209     connect( this, SIGNAL(askReleaseVideo( void )),
210              this, SLOT(releaseVideoSlot( void )),
211              Qt::BlockingQueuedConnection );
212     CONNECT( this, askVideoOnTop(bool), this, setVideoOnTop(bool));
213
214     if( videoWidget )
215     {
216         if( b_autoresize )
217         {
218             CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
219                      this, setVideoSize( unsigned int, unsigned int ) );
220             CONNECT( videoWidget, sizeChanged( int, int ),
221                      this, videoSizeChanged( int,  int ) );
222         }
223         CONNECT( this, askVideoSetFullScreen( bool ),
224                  this, setVideoFullScreen( bool ) );
225     }
226
227     CONNECT( THEDP, toolBarConfUpdated(), this, toolBarConfUpdated() );
228     installEventFilter( this );
229
230     CONNECT( this, askToQuit(), THEDP, quit() );
231
232     CONNECT( this, askBoss(), this, setBoss() );
233     CONNECT( this, askRaise(), this, setRaise() );
234
235     /** END of CONNECTS**/
236
237
238     /************
239      * Callbacks
240      ************/
241     var_AddCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
242     var_AddCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
243     var_AddCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, 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
249     /* Final Sizing, restoration and placement of the interface */
250     if( settings->value( "MainWindow/playlist-visible", false ).toBool() )
251         togglePlaylist();
252
253     QVLCTools::restoreWidgetPosition( settings, this, QSize(600, 420) );
254
255     b_interfaceFullScreen = isFullScreen();
256
257     setVisible( !b_hideAfterCreation );
258
259     /* Switch to minimal view if needed, must be called after the show() */
260     if( b_minimalView )
261         toggleMinimalView( true );
262
263     computeMinimumSize();
264 }
265
266 MainInterface::~MainInterface()
267 {
268     /* Unsure we hide the videoWidget before destroying it */
269     if( stackCentralOldWidget == videoWidget )
270         showTab( bgWidget );
271
272     if( videoWidget )
273         releaseVideoSlot();
274
275 #ifdef _WIN32
276     if( himl )
277         ImageList_Destroy( himl );
278     if(p_taskbl)
279         p_taskbl->Release();
280     CoUninitialize();
281 #endif
282
283     /* Be sure to kill the actionsManager... Only used in the MI and control */
284     ActionsManager::killInstance();
285
286     /* Delete the FSC controller */
287     delete fullscreenControls;
288
289     /* Save states */
290
291     settings->beginGroup("MainWindow");
292     settings->setValue( "pl-dock-status", b_plDocked );
293
294     /* Save playlist state */
295     settings->setValue( "playlist-visible", playlistVisible );
296
297     settings->setValue( "adv-controls",
298                         getControlsVisibilityStatus() & CONTROLS_ADVANCED );
299     settings->setValue( "status-bar-visible", b_statusbarVisible );
300
301     /* Save the stackCentralW sizes */
302     settings->setValue( "bgSize", stackWidgetsSizes[bgWidget] );
303     settings->setValue( "playlistSize", stackWidgetsSizes[playlistWidget] );
304     settings->endGroup();
305
306     /* Save this size */
307     QVLCTools::saveWidgetPosition(settings, this);
308
309     /* Unregister callbacks */
310     var_DelCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
311     var_DelCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
312     var_DelCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
313     var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
314
315     p_intf->p_sys->p_mi = NULL;
316 }
317
318 void MainInterface::computeMinimumSize()
319 {
320     int minWidth = 80;
321     if( menuBar()->isVisible() )
322         minWidth += controls->sizeHint().width();
323
324     setMinimumWidth( minWidth );
325 }
326
327 /*****************************
328  *   Main UI handling        *
329  *****************************/
330 void MainInterface::recreateToolbars()
331 {
332     bool b_adv = getControlsVisibilityStatus() & CONTROLS_ADVANCED;
333
334     delete controls;
335     delete inputC;
336
337     controls = new ControlsWidget( p_intf, b_adv, this );
338     inputC = new InputControlsWidget( p_intf, this );
339     mainLayout->insertWidget( 2, inputC );
340     mainLayout->insertWidget( settings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
341                               controls );
342
343     if( fullscreenControls )
344     {
345         delete fullscreenControls;
346         fullscreenControls = new FullscreenControllerWidget( p_intf, this );
347         CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
348                  this, handleKeyPress( QKeyEvent * ) );
349         THEMIM->requestVoutUpdate();
350     }
351
352     setMinimalView( b_minimalView );
353 }
354
355 void MainInterface::reloadPrefs()
356 {
357     i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
358     b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
359 #ifdef _WIN32
360     p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
361 #endif
362     if( !var_InheritBool( p_intf, "qt-fs-controller" ) && fullscreenControls )
363     {
364         delete fullscreenControls;
365         fullscreenControls = NULL;
366     }
367 }
368
369 void MainInterface::createResumePanel( QWidget *w )
370 {
371     resumePanel = new QWidget( w );
372     resumePanel->hide();
373     QHBoxLayout *resumePanelLayout = new QHBoxLayout( resumePanel );
374     resumePanelLayout->setSpacing( 0 ); resumePanelLayout->setMargin( 0 );
375
376     QLabel *continuePixmapLabel = new QLabel();
377     continuePixmapLabel->setPixmap( QPixmap( ":/menu/help" ) );
378     continuePixmapLabel->setContentsMargins( 5, 0, 5, 0 );
379
380     QLabel *continueLabel = new QLabel( qtr( "Do you want to restart the playback where left off?") );
381
382     QToolButton *cancel = new QToolButton( resumePanel );
383     cancel->setAutoRaise( true );
384     cancel->setText( "X" );
385
386     QPushButton *ok = new QPushButton( qtr( "&Continue" )  );
387
388     resumePanelLayout->addWidget( continuePixmapLabel );
389     resumePanelLayout->addWidget( continueLabel );
390     resumePanelLayout->addStretch( 1 );
391     resumePanelLayout->addWidget( ok );
392     resumePanelLayout->addWidget( cancel );
393
394     resumeTimer = new QTimer( resumePanel );
395     resumeTimer->setSingleShot( true );
396     resumeTimer->setInterval( 6000 );
397
398     CONNECT( resumeTimer, timeout(), this, hideResumePanel() );
399     CONNECT( cancel, clicked(), this, hideResumePanel() );
400     CONNECT( THEMIM->getIM(), resumePlayback(int64_t), this, showResumePanel(int64_t) );
401     BUTTONACT( ok, resumePlayback() );
402
403     w->layout()->addWidget( resumePanel );
404 }
405
406 void MainInterface::showResumePanel( int64_t _time ) {
407     int setting = var_InheritInteger( p_intf, "qt-continue" );
408
409     if( setting == 0 )
410         return;
411
412     i_resumeTime = _time;
413
414     if( setting == 2)
415         resumePlayback();
416     else
417     {
418         resumePanel->setVisible(true);
419         resumeTimer->start();
420     }
421 }
422
423 void MainInterface::hideResumePanel()
424 {
425     if( resumePanel->isVisible() )
426     {
427         if( !isFullScreen() && !isMaximized() )
428             resize( width(), height() - resumePanel->height() );
429         resumePanel->hide();
430         resumeTimer->stop();
431     }
432 }
433
434 void MainInterface::resumePlayback()
435 {
436     if( THEMIM->getIM()->hasInput() ) {
437         var_SetTime( THEMIM->getInput(), "time", i_resumeTime );
438     }
439     hideResumePanel();
440 }
441
442 void MainInterface::createMainWidget( QSettings *creationSettings )
443 {
444     /* Create the main Widget and the mainLayout */
445     QWidget *main = new QWidget;
446     setCentralWidget( main );
447     mainLayout = new QVBoxLayout( main );
448     main->setContentsMargins( 0, 0, 0, 0 );
449     mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
450
451     createResumePanel( main );
452     /* */
453     stackCentralW = new QVLCStackedWidget( main );
454
455     /* Bg Cone */
456     if ( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY
457          && var_InheritBool( p_intf, "qt-icon-change" ) )
458     {
459         bgWidget = new EasterEggBackgroundWidget( p_intf );
460         CONNECT( this, kc_pressed(), bgWidget, animate() );
461     }
462     else
463         bgWidget = new BackgroundWidget( p_intf );
464
465     stackCentralW->addWidget( bgWidget );
466     if ( !var_InheritBool( p_intf, "qt-bgcone" ) )
467         bgWidget->setWithArt( false );
468     else
469         if ( var_InheritBool( p_intf, "qt-bgcone-expands" ) )
470             bgWidget->setExpandstoHeight( true );
471
472     /* And video Outputs */
473     if( b_videoEmbedded )
474     {
475         videoWidget = new VideoWidget( p_intf );
476         stackCentralW->addWidget( videoWidget );
477     }
478     mainLayout->insertWidget( 1, stackCentralW );
479
480     stackWidgetsSizes[bgWidget] =
481         creationSettings->value( "MainWindow/bgSize", QSize( 600, 0 ) ).toSize();
482     /* Resize even if no-auto-resize, because we are at creation */
483     resizeStack( stackWidgetsSizes[bgWidget].width(), stackWidgetsSizes[bgWidget].height() );
484
485     /* Create the CONTROLS Widget */
486     controls = new ControlsWidget( p_intf,
487         creationSettings->value( "MainWindow/adv-controls", false ).toBool(), this );
488     inputC = new InputControlsWidget( p_intf, this );
489
490     mainLayout->insertWidget( 2, inputC );
491     mainLayout->insertWidget(
492         creationSettings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
493         controls );
494
495     /* Visualisation, disabled for now, they SUCK */
496     #if 0
497     visualSelector = new VisualSelector( p_intf );
498     mainLayout->insertWidget( 0, visualSelector );
499     visualSelector->hide();
500     #endif
501
502
503     /* Enable the popup menu in the MI */
504     main->setContextMenuPolicy( Qt::CustomContextMenu );
505     CONNECT( main, customContextMenuRequested( const QPoint& ),
506              THEDP, setPopupMenu() );
507
508     if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
509         /* Create the FULLSCREEN CONTROLS Widget */
510         if( var_InheritBool( p_intf, "qt-fs-controller" ) )
511         {
512             fullscreenControls = new FullscreenControllerWidget( p_intf, this );
513             CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
514                      this, handleKeyPress( QKeyEvent * ) );
515         }
516 }
517
518 inline void MainInterface::initSystray()
519 {
520     bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
521     bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
522
523     if( var_InheritBool( p_intf, "qt-start-minimized") )
524     {
525         if( b_systrayAvailable )
526         {
527             b_systrayWanted = true;
528             b_hideAfterCreation = true;
529         }
530         else
531             msg_Err( p_intf, "cannot start minimized without system tray bar" );
532     }
533
534     if( b_systrayAvailable && b_systrayWanted )
535         createSystray();
536 }
537
538 inline void MainInterface::createStatusBar()
539 {
540     /****************
541      *  Status Bar  *
542      ****************/
543     /* Widgets Creation*/
544     QStatusBar *statusBarr = statusBar();
545
546     TimeLabel *timeLabel = new TimeLabel( p_intf );
547     nameLabel = new ClickableQLabel();
548     nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
549                                       | Qt::TextSelectableByKeyboard );
550     SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
551
552     /* Styling those labels */
553     timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
554     speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
555     nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
556     timeLabel->setStyleSheet(
557             "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
558     speedLabel->setStyleSheet(
559             "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
560     /* pad both label and its tooltip */
561     nameLabel->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
562
563     /* and adding those */
564     statusBarr->addWidget( nameLabel, 8 );
565     statusBarr->addPermanentWidget( speedLabel, 0 );
566     statusBarr->addPermanentWidget( timeLabel, 0 );
567
568     CONNECT( nameLabel, doubleClicked(), THEDP, epgDialog() );
569     /* timeLabel behaviour:
570        - double clicking opens the goto time dialog
571        - right-clicking and clicking just toggle between remaining and
572          elapsed time.*/
573     CONNECT( timeLabel, doubleClicked(), THEDP, gotoTimeDialog() );
574
575     CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
576              this, showCryptedLabel( bool ) );
577
578     CONNECT( THEMIM->getIM(), seekRequested( float ),
579              timeLabel, setDisplayPosition( float ) );
580
581     /* This shouldn't be necessary, but for somehow reason, the statusBarr
582        starts at height of 20px and when a text is shown it needs more space.
583        But, as the QMainWindow policy doesn't allow statusBar to change QMW's
584        geometry, we need to force a height. If you have a better idea, please
585        tell me -- jb
586      */
587     statusBarr->setFixedHeight( statusBarr->sizeHint().height() + 2 );
588 }
589
590 /**********************************************************************
591  * Handling of sizing of the components
592  **********************************************************************/
593
594 void MainInterface::debug()
595 {
596 #ifdef DEBUG_INTF
597     if( controls ) {
598         msg_Dbg( p_intf, "Controls size: %i - %i", controls->size().height(), controls->size().width() );
599         msg_Dbg( p_intf, "Controls minimumsize: %i - %i", controls->minimumSize().height(), controls->minimumSize().width() );
600         msg_Dbg( p_intf, "Controls sizeHint: %i - %i", controls->sizeHint().height(), controls->sizeHint().width() );
601     }
602
603     msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
604     msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
605     msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
606
607     msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
608     msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
609     msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
610 #endif
611 }
612
613 inline void MainInterface::showVideo() { showTab( videoWidget ); setRaise(); }
614 inline void MainInterface::restoreStackOldWidget()
615             { showTab( stackCentralOldWidget ); }
616
617 inline void MainInterface::showTab( QWidget *widget )
618 {
619     if ( !widget ) widget = bgWidget; /* trying to restore a null oldwidget */
620 #ifdef DEBUG_INTF
621     if ( stackCentralOldWidget )
622         msg_Dbg( p_intf, "Old stackCentralOldWidget %s at index %i",
623                  stackCentralOldWidget->metaObject()->className(),
624                  stackCentralW->indexOf( stackCentralOldWidget ) );
625     msg_Dbg( p_intf, "ShowTab request for %s", widget->metaObject()->className() );
626 #endif
627     /* fixing when the playlist has been undocked after being hidden.
628        restoreStackOldWidget() is called when video stops but
629        stackCentralOldWidget would still be pointing to playlist */
630     if ( widget == playlistWidget && !isPlDocked() )
631         widget = bgWidget;
632
633     stackCentralOldWidget = stackCentralW->currentWidget();
634     stackWidgetsSizes[stackCentralOldWidget] = stackCentralW->size();
635
636     /* If we are playing video, embedded */
637     if( videoWidget && THEMIM->getIM()->hasVideo() )
638     {
639         /* Video -> Playlist */
640         if( videoWidget == stackCentralOldWidget && widget == playlistWidget )
641         {
642             stackCentralW->removeWidget( videoWidget );
643             videoWidget->show(); videoWidget->raise();
644         }
645
646         /* Playlist -> Video */
647         if( playlistWidget == stackCentralOldWidget && widget == videoWidget )
648         {
649             playlistWidget->artContainer->removeWidget( videoWidget );
650             videoWidget->show(); videoWidget->raise();
651             stackCentralW->addWidget( videoWidget );
652         }
653
654         /* Embedded playlist -> Non-embedded playlist */
655         if( bgWidget == stackCentralOldWidget && widget == videoWidget )
656         {
657             /* In rare case when video is started before the interface */
658             if( playlistWidget != NULL )
659                 playlistWidget->artContainer->removeWidget( videoWidget );
660             videoWidget->show(); videoWidget->raise();
661             stackCentralW->addWidget( videoWidget );
662             stackCentralW->setCurrentWidget( videoWidget );
663         }
664     }
665
666     stackCentralW->setCurrentWidget( widget );
667     if( b_autoresize )
668         resizeStack( stackWidgetsSizes[widget].width(), stackWidgetsSizes[widget].height() );
669
670 #ifdef DEBUG_INTF
671     msg_Dbg( p_intf, "Stack state changed to %s, index %i",
672               stackCentralW->currentWidget()->metaObject()->className(),
673               stackCentralW->currentIndex() );
674     msg_Dbg( p_intf, "New stackCentralOldWidget %s at index %i",
675               stackCentralOldWidget->metaObject()->className(),
676               stackCentralW->indexOf( stackCentralOldWidget ) );
677 #endif
678
679     /* This part is done later, to account for the new pl size */
680     if( videoWidget && THEMIM->getIM()->hasVideo() &&
681         videoWidget == stackCentralOldWidget && widget == playlistWidget )
682     {
683         playlistWidget->artContainer->addWidget( videoWidget );
684         playlistWidget->artContainer->setCurrentWidget( videoWidget );
685     }
686 }
687
688 void MainInterface::toggleFSC()
689 {
690    if( !fullscreenControls ) return;
691
692    IMEvent *eShow = new IMEvent( IMEvent::FullscreenControlToggle );
693    QApplication::postEvent( fullscreenControls, eShow );
694 }
695
696 /****************************************************************************
697  * Video Handling
698  ****************************************************************************/
699
700 /**
701  * NOTE:
702  * You must not change the state of this object or other Qt UI objects,
703  * from the video output thread - only from the Qt UI main loop thread.
704  * All window provider queries must be handled through signals or events.
705  * That's why we have all those emit statements...
706  */
707 WId MainInterface::getVideo( struct vout_window_t *p_wnd,
708                              unsigned int *pi_width, unsigned int *pi_height )
709 {
710     if( !videoWidget )
711         return 0;
712
713     /* This is a blocking call signal. Results are returned through pointers.
714      * Beware of deadlocks! */
715     WId id;
716     emit askGetVideo( &id, p_wnd, pi_width, pi_height );
717     return id;
718 }
719
720 void MainInterface::getVideoSlot( WId *p_id, struct vout_window_t *p_wnd,
721                                   unsigned *pi_width, unsigned *pi_height )
722 {
723     /* Hidden or minimized, activate */
724     if( isHidden() || isMinimized() )
725         toggleUpdateSystrayMenu();
726
727     /* Request the videoWidget */
728     WId ret = videoWidget->request( p_wnd, pi_width, pi_height, !b_autoresize );
729     *p_id = ret;
730     if( ret ) /* The videoWidget is available */
731     {
732         /* Consider the video active now */
733         showVideo();
734
735         /* Ask videoWidget to resize correctly, if we are in normal mode */
736         if( !isFullScreen() && !isMaximized() && b_autoresize )
737             videoWidget->SetSizing( *pi_width, *pi_height );
738     }
739 }
740
741 /* Asynchronous call from the WindowClose function */
742 void MainInterface::releaseVideo( void )
743 {
744     emit askReleaseVideo();
745 }
746
747 /* Function that is CONNECTED to the previous emit */
748 void MainInterface::releaseVideoSlot( void )
749 {
750     /* This function is called when the embedded video window is destroyed,
751      * or in the rare case that the embedded window is still here but the
752      * Qt interface exits. */
753     assert( videoWidget );
754     videoWidget->release();
755     setVideoOnTop( false );
756     setVideoFullScreen( false );
757     hideResumePanel();
758
759     if( stackCentralW->currentWidget() == videoWidget )
760         restoreStackOldWidget();
761     else if( playlistWidget &&
762              playlistWidget->artContainer->currentWidget() == videoWidget )
763     {
764         playlistWidget->artContainer->setCurrentIndex( 0 );
765         stackCentralW->addWidget( videoWidget );
766     }
767
768     /* We don't want to have a blank video to popup */
769     stackCentralOldWidget = bgWidget;
770 }
771
772 void MainInterface::setVideoSize( unsigned int w, unsigned int h )
773 {
774     if( !isFullScreen() && !isMaximized() )
775         videoWidget->SetSizing( w, h );
776 }
777
778 void MainInterface::videoSizeChanged( int w, int h )
779 {
780     if( !playlistWidget || playlistWidget->artContainer->currentWidget() != videoWidget )
781         resizeStack( w, h );
782 }
783
784 void MainInterface::setVideoFullScreen( bool fs )
785 {
786     b_videoFullScreen = fs;
787     if( fs )
788     {
789         int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
790         /* if user hasn't defined screennumber, or screennumber that is bigger
791          * than current number of screens, take screennumber where current interface
792          * is
793          */
794         if( numscreen == -1 || numscreen > QApplication::desktop()->numScreens() )
795             numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
796
797         QRect screenres = QApplication::desktop()->screenGeometry( numscreen );
798
799         /* To be sure window is on proper-screen in xinerama */
800         if( !screenres.contains( pos() ) )
801         {
802             msg_Dbg( p_intf, "Moving video to correct screen");
803             move( QPoint( screenres.x(), screenres.y() ) );
804         }
805
806         /* */
807         if( playlistWidget != NULL && playlistWidget->artContainer->currentWidget() == videoWidget )
808         {
809             showTab( videoWidget );
810         }
811
812         /* */
813         setMinimalView( true );
814         setInterfaceFullScreen( true );
815     }
816     else
817     {
818         /* TODO do we want to restore screen and position ? (when
819          * qt-fullscreen-screennumber is forced) */
820         setMinimalView( b_minimalView );
821         setInterfaceFullScreen( b_interfaceFullScreen );
822 #ifdef _WIN32
823         changeThumbbarButtons( THEMIM->getIM()->playingStatus() );
824 #endif
825     }
826     videoWidget->sync();
827 }
828
829 /* Slot to change the video always-on-top flag.
830  * Emit askVideoOnTop() to invoke this from other thread. */
831 void MainInterface::setVideoOnTop( bool on_top )
832 {
833     Qt::WindowFlags oldflags = windowFlags(), newflags;
834
835     if( on_top )
836         newflags = oldflags | Qt::WindowStaysOnTopHint;
837     else
838         newflags = oldflags & ~Qt::WindowStaysOnTopHint;
839     if( newflags != oldflags && !b_videoFullScreen )
840
841     {
842         setWindowFlags( newflags );
843         show(); /* necessary to apply window flags */
844     }
845 }
846
847 /* Asynchronous call from WindowControl function */
848 int MainInterface::controlVideo( int i_query, va_list args )
849 {
850     switch( i_query )
851     {
852     case VOUT_WINDOW_SET_SIZE:
853     {
854         unsigned int i_width  = va_arg( args, unsigned int );
855         unsigned int i_height = va_arg( args, unsigned int );
856
857         emit askVideoToResize( i_width, i_height );
858         return VLC_SUCCESS;
859     }
860     case VOUT_WINDOW_SET_STATE:
861     {
862         unsigned i_arg = va_arg( args, unsigned );
863         unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
864
865         emit askVideoOnTop( on_top != 0 );
866         return VLC_SUCCESS;
867     }
868     case VOUT_WINDOW_SET_FULLSCREEN:
869     {
870         bool b_fs = va_arg( args, int );
871
872         emit askVideoSetFullScreen( b_fs );
873         return VLC_SUCCESS;
874     }
875     default:
876         msg_Warn( p_intf, "unsupported control query" );
877         return VLC_EGENERIC;
878     }
879 }
880
881 /*****************************************************************************
882  * Playlist, Visualisation and Menus handling
883  *****************************************************************************/
884 /**
885  * Toggle the playlist widget or dialog
886  **/
887 void MainInterface::createPlaylist()
888 {
889     PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
890
891     if( b_plDocked )
892     {
893         playlistWidget = dialog->exportPlaylistWidget();
894         stackCentralW->addWidget( playlistWidget );
895         stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 600, 300 ) ).toSize();
896     }
897     CONNECT( dialog, visibilityChanged(bool), this, setPlaylistVisibility(bool) );
898 }
899
900 void MainInterface::togglePlaylist()
901 {
902     if( !playlistWidget ) createPlaylist();
903
904     PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
905     if( b_plDocked )
906     {
907         if ( dialog->hasPlaylistWidget() )
908             playlistWidget = dialog->exportPlaylistWidget();
909         /* Playlist is not visible, show it */
910         if( stackCentralW->currentWidget() != playlistWidget )
911         {
912             if( stackCentralW->indexOf( playlistWidget ) == -1 )
913                 stackCentralW->addWidget( playlistWidget );
914             showTab( playlistWidget );
915         }
916         else /* Hide it! */
917         {
918             restoreStackOldWidget();
919         }
920         playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
921     }
922     else
923     {
924         playlistVisible = !playlistVisible;
925         if ( ! dialog->hasPlaylistWidget() )
926             dialog->importPlaylistWidget( playlistWidget );
927         if ( playlistVisible )
928             dialog->show();
929         else
930             dialog->hide();
931     }
932     debug();
933 }
934
935 const Qt::Key MainInterface::kc[10] =
936 {
937     Qt::Key_Up, Qt::Key_Up,
938     Qt::Key_Down, Qt::Key_Down,
939     Qt::Key_Left, Qt::Key_Right, Qt::Key_Left, Qt::Key_Right,
940     Qt::Key_B, Qt::Key_A
941 };
942
943 void MainInterface::dockPlaylist( bool p_docked )
944 {
945     if( b_plDocked == p_docked ) return;
946     /* some extra check */
947     if ( b_plDocked && !playlistWidget ) createPlaylist();
948
949     b_plDocked = p_docked;
950     PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
951
952     if( !p_docked ) /* Previously docked */
953     {
954         playlistVisible = playlistWidget->isVisible();
955         stackCentralW->removeWidget( playlistWidget );
956         dialog->importPlaylistWidget( playlistWidget );
957         if ( playlistVisible ) dialog->show();
958         restoreStackOldWidget();
959     }
960     else /* Previously undocked */
961     {
962         playlistVisible = dialog->isVisible();
963         dialog->hide();
964         playlistWidget = dialog->exportPlaylistWidget();
965         stackCentralW->addWidget( playlistWidget );
966
967         /* If playlist is invisible don't show it */
968         if( playlistVisible ) showTab( playlistWidget );
969     }
970 }
971
972 /*
973  * setMinimalView is the private function used by
974  * the SLOT toggleMinimalView and setVideoFullScreen
975  */
976 void MainInterface::setMinimalView( bool b_minimal )
977 {
978     menuBar()->setVisible( !b_minimal );
979     controls->setVisible( !b_minimal );
980     statusBar()->setVisible( !b_minimal && b_statusbarVisible );
981     inputC->setVisible( !b_minimal );
982 }
983
984 /*
985  * This public SLOT is used for moving to minimal View Mode
986  *
987  * If b_minimal is false, then we are normalView
988  */
989 void MainInterface::toggleMinimalView( bool b_minimal )
990 {
991     if( !b_minimalView && b_autoresize ) /* Normal mode */
992     {
993         if( stackCentralW->currentWidget() == bgWidget )
994         {
995             if( stackCentralW->height() < 16 )
996             {
997                 resizeStack( stackCentralW->width(), 100 );
998             }
999         }
1000     }
1001     b_minimalView = b_minimal;
1002     if( !b_videoFullScreen )
1003     {
1004         setMinimalView( b_minimalView );
1005         computeMinimumSize();
1006     }
1007
1008     emit minimalViewToggled( b_minimalView );
1009 }
1010
1011 /* toggling advanced controls buttons */
1012 void MainInterface::toggleAdvancedButtons()
1013 {
1014     controls->toggleAdvanced();
1015 //    if( fullscreenControls ) fullscreenControls->toggleAdvanced();
1016 }
1017
1018 /* Get the visibility status of the controls (hidden or not, advanced or not) */
1019 int MainInterface::getControlsVisibilityStatus()
1020 {
1021     if( !controls ) return 0;
1022     return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
1023             + CONTROLS_ADVANCED * controls->b_advancedVisible );
1024 }
1025
1026 StandardPLPanel *MainInterface::getPlaylistView()
1027 {
1028     if( !playlistWidget ) return NULL;
1029     else return playlistWidget->mainView;
1030 }
1031
1032 void MainInterface::setStatusBarVisibility( bool b_visible )
1033 {
1034     statusBar()->setVisible( b_visible );
1035     b_statusbarVisible = b_visible;
1036     if( controls ) controls->setGripVisible( !b_statusbarVisible );
1037 }
1038
1039
1040 void MainInterface::setPlaylistVisibility( bool b_visible )
1041 {
1042     if( isPlDocked() || THEDP->isDying() || (playlistWidget && playlistWidget->isMinimized() ) )
1043         return;
1044
1045     playlistVisible = b_visible;
1046 }
1047
1048 #if 0
1049 void MainInterface::visual()
1050 {
1051     if( !VISIBLE( visualSelector) )
1052     {
1053         visualSelector->show();
1054         if( !THEMIM->getIM()->hasVideo() )
1055         {
1056             /* Show the background widget */
1057         }
1058         visualSelectorEnabled = true;
1059     }
1060     else
1061     {
1062         /* Stop any currently running visualization */
1063         visualSelector->hide();
1064         visualSelectorEnabled = false;
1065     }
1066 }
1067 #endif
1068
1069 /************************************************************************
1070  * Other stuff
1071  ************************************************************************/
1072 void MainInterface::setName( const QString& name )
1073 {
1074     input_name = name; /* store it for the QSystray use */
1075     /* Display it in the status bar, but also as a Tooltip in case it doesn't
1076        fit in the label */
1077     nameLabel->setText( name );
1078     nameLabel->setToolTip( name );
1079 }
1080
1081 /**
1082  * Give the decorations of the Main Window a correct Name.
1083  * If nothing is given, set it to VLC...
1084  **/
1085 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
1086 {
1087     if( aTitle.isEmpty() )
1088     {
1089         setWindowTitle( qtr( "VLC media player" ) );
1090     }
1091     else
1092     {
1093         setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
1094     }
1095 }
1096
1097 void MainInterface::showCryptedLabel( bool b_show )
1098 {
1099     if( cryptedLabel == NULL )
1100     {
1101         cryptedLabel = new QLabel;
1102         // The lock icon is not the right one for DRM protection/scrambled.
1103         //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
1104         cryptedLabel->setText( "DRM" );
1105         statusBar()->addWidget( cryptedLabel );
1106     }
1107
1108     cryptedLabel->setVisible( b_show );
1109 }
1110
1111 void MainInterface::showBuffering( float f_cache )
1112 {
1113     QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
1114     statusBar()->showMessage( amount, 1000 );
1115 }
1116
1117 /*****************************************************************************
1118  * Systray Icon and Systray Menu
1119  *****************************************************************************/
1120 /**
1121  * Create a SystemTray icon and a menu that would go with it.
1122  * Connects to a click handler on the icon.
1123  **/
1124 void MainInterface::createSystray()
1125 {
1126     QIcon iconVLC;
1127     if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
1128         iconVLC = QIcon::fromTheme( "vlc-xmas", QIcon( ":/logo/vlc128-xmas.png" ) );
1129     else
1130         iconVLC = QIcon::fromTheme( "vlc", QIcon( ":/logo/vlc256.png" ) );
1131     sysTray = new QSystemTrayIcon( iconVLC, this );
1132     sysTray->setToolTip( qtr( "VLC media player" ));
1133
1134     systrayMenu = new QMenu( qtr( "VLC media player" ), this );
1135     systrayMenu->setIcon( iconVLC );
1136
1137     VLCMenuBar::updateSystrayMenu( this, p_intf, true );
1138     sysTray->show();
1139
1140     CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
1141              this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
1142
1143     /* Connects on nameChanged() */
1144     CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
1145              this, updateSystrayTooltipName( const QString& ) );
1146     /* Connect PLAY_STATUS on the systray */
1147     CONNECT( THEMIM->getIM(), playingStatusChanged( int ),
1148              this, updateSystrayTooltipStatus( int ) );
1149 }
1150
1151 /**
1152  * Updates the Systray Icon's menu and toggle the main interface
1153  */
1154 void MainInterface::toggleUpdateSystrayMenu()
1155 {
1156     /* If hidden, show it */
1157     if( isHidden() )
1158     {
1159         show();
1160         activateWindow();
1161     }
1162     else if( isMinimized() )
1163     {
1164         /* Minimized */
1165         showNormal();
1166         activateWindow();
1167     }
1168     else
1169     {
1170         /* Visible (possibly under other windows) */
1171 #ifdef _WIN32
1172         /* check if any visible window is above vlc in the z-order,
1173          * but ignore the ones always on top
1174          * and the ones which can't be activated */
1175         HWND winId;
1176 #if HAS_QT5
1177         QWindow *window = windowHandle();
1178         winId = static_cast<HWND>(QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", window));
1179 #else
1180         winId = internalWinId();
1181 #endif
1182
1183         WINDOWINFO wi;
1184         HWND hwnd;
1185         wi.cbSize = sizeof( WINDOWINFO );
1186         for( hwnd = GetNextWindow( winId, GW_HWNDPREV );
1187                 hwnd && ( !IsWindowVisible( hwnd ) ||
1188                     ( GetWindowInfo( hwnd, &wi ) &&
1189                       (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
1190                 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
1191             if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
1192                 (wi.dwExStyle&WS_EX_TOPMOST) )
1193             {
1194                 hide();
1195             }
1196             else
1197             {
1198                 activateWindow();
1199             }
1200 #else
1201         hide();
1202 #endif // _WIN32
1203     }
1204     if( sysTray )
1205         VLCMenuBar::updateSystrayMenu( this, p_intf );
1206 }
1207
1208 /* First Item of the systray menu */
1209 void MainInterface::showUpdateSystrayMenu()
1210 {
1211     if( isHidden() )
1212         show();
1213     if( isMinimized() )
1214         showNormal();
1215     activateWindow();
1216
1217     VLCMenuBar::updateSystrayMenu( this, p_intf );
1218 }
1219
1220 /* First Item of the systray menu */
1221 void MainInterface::hideUpdateSystrayMenu()
1222 {
1223     hide();
1224     VLCMenuBar::updateSystrayMenu( this, p_intf );
1225 }
1226
1227 /* Click on systray Icon */
1228 void MainInterface::handleSystrayClick(
1229                                     QSystemTrayIcon::ActivationReason reason )
1230 {
1231     switch( reason )
1232     {
1233         case QSystemTrayIcon::Trigger:
1234         case QSystemTrayIcon::DoubleClick:
1235 #ifdef Q_OS_MAC
1236             VLCMenuBar::updateSystrayMenu( this, p_intf );
1237 #else
1238             toggleUpdateSystrayMenu();
1239 #endif
1240             break;
1241         case QSystemTrayIcon::MiddleClick:
1242             sysTray->showMessage( qtr( "VLC media player" ),
1243                     qtr( "Control menu for the player" ),
1244                     QSystemTrayIcon::Information, 3000 );
1245             break;
1246         default:
1247             break;
1248     }
1249 }
1250
1251 /**
1252  * Updates the name of the systray Icon tooltip.
1253  * Doesn't check if the systray exists, check before you call it.
1254  **/
1255 void MainInterface::updateSystrayTooltipName( const QString& name )
1256 {
1257     if( name.isEmpty() )
1258     {
1259         sysTray->setToolTip( qtr( "VLC media player" ) );
1260     }
1261     else
1262     {
1263         sysTray->setToolTip( name );
1264         if( ( i_notificationSetting == NOTIFICATION_ALWAYS ) ||
1265             ( i_notificationSetting == NOTIFICATION_MINIMIZED && (isMinimized() || isHidden()) ) )
1266         {
1267             sysTray->showMessage( qtr( "VLC media player" ), name,
1268                     QSystemTrayIcon::NoIcon, 3000 );
1269         }
1270     }
1271
1272     VLCMenuBar::updateSystrayMenu( this, p_intf );
1273 }
1274
1275 /**
1276  * Updates the status of the systray Icon tooltip.
1277  * Doesn't check if the systray exists, check before you call it.
1278  **/
1279 void MainInterface::updateSystrayTooltipStatus( int i_status )
1280 {
1281     switch( i_status )
1282     {
1283     case PLAYING_S:
1284         sysTray->setToolTip( input_name );
1285         break;
1286     case PAUSE_S:
1287         sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1288         break;
1289     default:
1290         sysTray->setToolTip( qtr( "VLC media player" ) );
1291         break;
1292     }
1293     VLCMenuBar::updateSystrayMenu( this, p_intf );
1294 }
1295
1296 void MainInterface::changeEvent(QEvent *event)
1297 {
1298     if( event->type() == QEvent::WindowStateChange )
1299     {
1300         QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
1301         Qt::WindowStates newState = windowState();
1302         Qt::WindowStates oldState = windowStateChangeEvent->oldState();
1303
1304         if( newState & Qt::WindowMinimized )
1305         {
1306             b_hasPausedWhenMinimized = false;
1307
1308             if( THEMIM->getIM()->playingStatus() == PLAYING_S &&
1309                 THEMIM->getIM()->hasVideo() && !THEMIM->getIM()->hasVisualisation() &&
1310                 b_pauseOnMinimize )
1311             {
1312                 b_hasPausedWhenMinimized = true;
1313                 THEMIM->pause();
1314             }
1315         }
1316         else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
1317         {
1318             if( b_hasPausedWhenMinimized )
1319             {
1320                 THEMIM->play();
1321             }
1322         }
1323     }
1324
1325     QWidget::changeEvent(event);
1326 }
1327
1328 /************************************************************************
1329  * D&D Events
1330  ************************************************************************/
1331 void MainInterface::dropEvent(QDropEvent *event)
1332 {
1333     dropEventPlay( event, true );
1334 }
1335
1336 /**
1337  * dropEventPlay
1338  *
1339  * Event called if something is dropped onto a VLC window
1340  * \param event the event in question
1341  * \param b_play whether to play the file immediately
1342  * \param b_playlist true to add to playlist, false to add to media library
1343  * \return nothing
1344  */
1345 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play, bool b_playlist )
1346 {
1347     if( event->possibleActions() & ( Qt::CopyAction | Qt::MoveAction | Qt::LinkAction ) )
1348        event->setDropAction( Qt::CopyAction );
1349     else
1350         return;
1351
1352     const QMimeData *mimeData = event->mimeData();
1353
1354     /* D&D of a subtitles file, add it on the fly */
1355     if( mimeData->urls().count() == 1 && THEMIM->getIM()->hasInput() )
1356     {
1357         if( !input_AddSubtitleOSD( THEMIM->getInput(),
1358                  qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1359                  true, true ) )
1360         {
1361             event->accept();
1362             return;
1363         }
1364     }
1365
1366     bool first = b_play;
1367     foreach( const QUrl &url, mimeData->urls() )
1368     {
1369         if( url.isValid() )
1370         {
1371             QString mrl = toURI( url.toEncoded().constData() );
1372             QFileInfo info( url.toLocalFile() );
1373             if( info.exists() && info.isSymLink() )
1374             {
1375                 QString target = info.symLinkTarget();
1376                 QUrl url;
1377                 if( QFile::exists( target ) )
1378                 {
1379                     url = QUrl::fromLocalFile( target );
1380                 }
1381                 else
1382                 {
1383                     url.setUrl( target );
1384                 }
1385                 mrl = toURI( url.toEncoded().constData() );
1386             }
1387             if( mrl.length() > 0 )
1388             {
1389                 Open::openMRL( p_intf, mrl, first, b_playlist );
1390                 first = false;
1391             }
1392         }
1393     }
1394
1395     /* Browsers give content as text if you dnd the addressbar,
1396        so check if mimedata has valid url in text and use it
1397        if we didn't get any normal Urls()*/
1398     if( !mimeData->hasUrls() && mimeData->hasText() &&
1399         QUrl(mimeData->text()).isValid() )
1400     {
1401         QString mrl = toURI( mimeData->text() );
1402         Open::openMRL( p_intf, mrl, first, b_playlist );
1403     }
1404     event->accept();
1405 }
1406 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1407 {
1408      event->acceptProposedAction();
1409 }
1410 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1411 {
1412      event->acceptProposedAction();
1413 }
1414 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1415 {
1416      event->accept();
1417 }
1418
1419 /************************************************************************
1420  * Events stuff
1421  ************************************************************************/
1422 void MainInterface::keyPressEvent( QKeyEvent *e )
1423 {
1424     handleKeyPress( e );
1425
1426     /* easter eggs sequence handling */
1427     if ( e->key() == kc[ i_kc_offset ] )
1428         i_kc_offset++;
1429     else
1430         i_kc_offset = 0;
1431
1432     if ( i_kc_offset == (sizeof( kc ) / sizeof( Qt::Key )) )
1433     {
1434         i_kc_offset = 0;
1435         emit kc_pressed();
1436     }
1437 }
1438
1439 void MainInterface::handleKeyPress( QKeyEvent *e )
1440 {
1441     if( ( ( e->modifiers() & Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) ) ||
1442         ( b_minimalView && !b_videoFullScreen && e->key() == Qt::Key_Escape ) )
1443     {
1444         toggleMinimalView( !b_minimalView );
1445         e->accept();
1446     }
1447
1448     int i_vlck = qtEventToVLCKey( e );
1449     if( i_vlck > 0 )
1450     {
1451         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1452         e->accept();
1453     }
1454     else
1455         e->ignore();
1456 }
1457
1458 void MainInterface::wheelEvent( QWheelEvent *e )
1459 {
1460     int i_vlckey = qtWheelEventToVLCKey( e );
1461     var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1462     e->accept();
1463 }
1464
1465 void MainInterface::closeEvent( QCloseEvent *e )
1466 {
1467 //  hide();
1468     emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
1469     /* Accept session quit. Otherwise we break the desktop mamager. */
1470     e->accept();
1471 }
1472
1473 bool MainInterface::eventFilter( QObject *obj, QEvent *event )
1474 {
1475     if ( event->type() == MainInterface::ToolbarsNeedRebuild ) {
1476         event->accept();
1477         recreateToolbars();
1478         return true;
1479     } else {
1480         return QObject::eventFilter( obj, event );
1481     }
1482 }
1483
1484 void MainInterface::toolBarConfUpdated()
1485 {
1486     QApplication::postEvent( this, new QEvent( MainInterface::ToolbarsNeedRebuild ) );
1487 }
1488
1489 void MainInterface::setInterfaceFullScreen( bool fs )
1490 {
1491     if( fs )
1492         setWindowState( windowState() | Qt::WindowFullScreen );
1493     else
1494         setWindowState( windowState() & ~Qt::WindowFullScreen );
1495 }
1496 void MainInterface::toggleInterfaceFullScreen()
1497 {
1498     b_interfaceFullScreen = !b_interfaceFullScreen;
1499     if( !b_videoFullScreen )
1500         setInterfaceFullScreen( b_interfaceFullScreen );
1501     emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1502 }
1503
1504 void MainInterface::emitBoss()
1505 {
1506     emit askBoss();
1507 }
1508 void MainInterface::setBoss()
1509 {
1510     THEMIM->pause();
1511     if( sysTray )
1512     {
1513         hide();
1514     }
1515     else
1516     {
1517         showMinimized();
1518     }
1519 }
1520
1521 void MainInterface::emitRaise()
1522 {
1523     emit askRaise();
1524 }
1525 void MainInterface::setRaise()
1526 {
1527     activateWindow();
1528     raise();
1529 }
1530
1531 /*****************************************************************************
1532  * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1533  *  We don't show the menu directly here because we don't want the
1534  *  caller to block for a too long time.
1535  *****************************************************************************/
1536 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1537                         vlc_value_t old_val, vlc_value_t new_val, void *param )
1538 {
1539     VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1540
1541     intf_thread_t *p_intf = (intf_thread_t *)param;
1542
1543     if( p_intf->pf_show_dialog )
1544     {
1545         p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1546                                 new_val.b_bool, NULL );
1547     }
1548
1549     return VLC_SUCCESS;
1550 }
1551
1552 /*****************************************************************************
1553  * IntfShowCB: callback triggered by the intf-toggle-fscontrol libvlc variable.
1554  *****************************************************************************/
1555 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1556                        vlc_value_t old_val, vlc_value_t new_val, void *param )
1557 {
1558     VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1559     VLC_UNUSED( new_val );
1560
1561     intf_thread_t *p_intf = (intf_thread_t *)param;
1562     p_intf->p_sys->p_mi->toggleFSC();
1563
1564     /* Show event */
1565      return VLC_SUCCESS;
1566 }
1567
1568 /*****************************************************************************
1569  * IntfRaiseMainCB: callback triggered by the intf-show-main libvlc variable.
1570  *****************************************************************************/
1571 static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
1572                        vlc_value_t old_val, vlc_value_t new_val, void *param )
1573 {
1574     VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1575     VLC_UNUSED( new_val );
1576
1577     intf_thread_t *p_intf = (intf_thread_t *)param;
1578     p_intf->p_sys->p_mi->emitRaise();
1579
1580     return VLC_SUCCESS;
1581 }
1582
1583 /*****************************************************************************
1584  * IntfBossCB: callback triggered by the intf-boss libvlc variable.
1585  *****************************************************************************/
1586 static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
1587                        vlc_value_t old_val, vlc_value_t new_val, void *param )
1588 {
1589     VLC_UNUSED( p_this ); VLC_UNUSED( psz_variable ); VLC_UNUSED( old_val );
1590     VLC_UNUSED( new_val );
1591
1592     intf_thread_t *p_intf = (intf_thread_t *)param;
1593     p_intf->p_sys->p_mi->emitBoss();
1594
1595     return VLC_SUCCESS;
1596 }