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