]> git.sesse.net Git - vlc/blob - modules/gui/qt4/main_interface.cpp
Qt: make the MainInterface Grey Brushed on Mac
[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             toggleUpdateSystrayMenu();
975             break;
976         case QSystemTrayIcon::MiddleClick:
977             sysTray->showMessage( qtr( "VLC media player" ),
978                     qtr( "Control menu for the player" ),
979                     QSystemTrayIcon::Information, 3000 );
980             break;
981         default:
982             break;
983     }
984 }
985
986 /**
987  * Updates the name of the systray Icon tooltip.
988  * Doesn't check if the systray exists, check before you call it.
989  **/
990 void MainInterface::updateSystrayTooltipName( const QString& name )
991 {
992     if( name.isEmpty() )
993     {
994         sysTray->setToolTip( qtr( "VLC media player" ) );
995     }
996     else
997     {
998         sysTray->setToolTip( name );
999         if( b_notificationEnabled && ( isHidden() || isMinimized() ) )
1000         {
1001             sysTray->showMessage( qtr( "VLC media player" ), name,
1002                     QSystemTrayIcon::NoIcon, 3000 );
1003         }
1004     }
1005
1006     QVLCMenu::updateSystrayMenu( this, p_intf );
1007 }
1008
1009 /**
1010  * Updates the status of the systray Icon tooltip.
1011  * Doesn't check if the systray exists, check before you call it.
1012  **/
1013 void MainInterface::updateSystrayTooltipStatus( int i_status )
1014 {
1015     switch( i_status )
1016     {
1017     case PLAYING_S:
1018         sysTray->setToolTip( input_name );
1019         break;
1020     case PAUSE_S:
1021         sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1022         break;
1023     default:
1024         sysTray->setToolTip( qtr( "VLC media player" ) );
1025         break;
1026     }
1027     QVLCMenu::updateSystrayMenu( this, p_intf );
1028 }
1029 #endif
1030
1031 /************************************************************************
1032  * D&D Events
1033  ************************************************************************/
1034 void MainInterface::dropEvent(QDropEvent *event)
1035 {
1036     dropEventPlay( event, true );
1037 }
1038
1039 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play )
1040 {
1041     if( event->possibleActions() & Qt::CopyAction )
1042        event->setDropAction( Qt::CopyAction );
1043     else
1044         return;
1045
1046     const QMimeData *mimeData = event->mimeData();
1047
1048     /* D&D of a subtitles file, add it on the fly */
1049     if( mimeData->urls().size() == 1 && THEMIM->getIM()->hasInput() )
1050     {
1051         if( !input_AddSubtitle( THEMIM->getInput(),
1052                  qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1053                  true ) )
1054         {
1055             event->accept();
1056             return;
1057         }
1058     }
1059
1060     bool first = b_play;
1061     foreach( const QUrl &url, mimeData->urls() )
1062     {
1063         if( url.isValid() )
1064         {
1065             char* psz_uri = make_URI( qtu( url.toString() ), NULL );
1066             playlist_Add( THEPL, psz_uri, NULL,
1067                           PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1068                           PLAYLIST_END, true, pl_Unlocked );
1069             free( psz_uri );
1070             first = false;
1071             RecentsMRL::getInstance( p_intf )->addRecent( url.toString() );
1072         }
1073     }
1074
1075     /* Browsers give content as text if you dnd the addressbar,
1076        so check if mimedata has valid url in text and use it
1077        if we didn't get any normal Urls()*/
1078     if( !mimeData->hasUrls() && mimeData->hasText() &&
1079         QUrl(mimeData->text()).isValid() )
1080     {
1081         char *psz_uri = make_URI( qtu( mimeData->text() ), NULL );
1082         playlist_Add( THEPL, psz_uri, NULL,
1083                       PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1084                       PLAYLIST_END, true, pl_Unlocked );
1085         free( psz_uri );
1086     }
1087     event->accept();
1088 }
1089 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1090 {
1091      event->acceptProposedAction();
1092 }
1093 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1094 {
1095      event->acceptProposedAction();
1096 }
1097 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1098 {
1099      event->accept();
1100 }
1101
1102 /************************************************************************
1103  * Events stuff
1104  ************************************************************************/
1105 void MainInterface::keyPressEvent( QKeyEvent *e )
1106 {
1107     handleKeyPress( e );
1108 }
1109
1110 void MainInterface::handleKeyPress( QKeyEvent *e )
1111 {
1112     if( ( e->modifiers() &  Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) )
1113     {
1114         toggleMinimalView( !b_minimalView );
1115         e->accept();
1116     }
1117
1118     int i_vlck = qtEventToVLCKey( e );
1119     if( i_vlck > 0 )
1120     {
1121         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1122         e->accept();
1123     }
1124     else
1125         e->ignore();
1126 }
1127
1128 void MainInterface::wheelEvent( QWheelEvent *e )
1129 {
1130     int i_vlckey = qtWheelEventToVLCKey( e );
1131     var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1132     e->accept();
1133 }
1134
1135 void MainInterface::closeEvent( QCloseEvent *e )
1136 {
1137     e->accept();
1138     hide();
1139     THEDP->quit();
1140 }
1141
1142 void MainInterface::setInterfaceFullScreen( bool fs )
1143 {
1144     if( fs )
1145         setWindowState( windowState() | Qt::WindowFullScreen );
1146     else
1147         setWindowState( windowState() & ~Qt::WindowFullScreen );
1148 }
1149 void MainInterface::toggleInterfaceFullScreen()
1150 {
1151     b_interfaceFullScreen = !b_interfaceFullScreen;
1152     if( !b_videoFullScreen )
1153         setInterfaceFullScreen( b_interfaceFullScreen );
1154     emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1155 }
1156
1157 /*****************************************************************************
1158  * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1159  *  We don't show the menu directly here because we don't want the
1160  *  caller to block for a too long time.
1161  *****************************************************************************/
1162 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1163                         vlc_value_t old_val, vlc_value_t new_val, void *param )
1164 {
1165     intf_thread_t *p_intf = (intf_thread_t *)param;
1166
1167     if( p_intf->pf_show_dialog )
1168     {
1169         p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1170                                 new_val.b_bool, NULL );
1171     }
1172
1173     return VLC_SUCCESS;
1174 }
1175
1176 /*****************************************************************************
1177  * IntfShowCB: callback triggered by the intf-show libvlc variable.
1178  *****************************************************************************/
1179 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1180                        vlc_value_t old_val, vlc_value_t new_val, void *param )
1181 {
1182     intf_thread_t *p_intf = (intf_thread_t *)param;
1183     p_intf->p_sys->p_mi->toggleFSC();
1184
1185     /* Show event */
1186      return VLC_SUCCESS;
1187 }