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