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