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