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