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