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