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