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