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