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