]> git.sesse.net Git - vlc/blob - modules/gui/qt4/main_interface.cpp
Qt: fix main_interface sizing part 2
[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
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 #ifndef HAVE_MAEMO
79     sysTray              = NULL;
80 #endif
81     fullscreenControls   = NULL;
82     cryptedLabel         = NULL;
83     controls             = NULL;
84     inputC               = NULL;
85
86     b_hideAfterCreation  = false; // --qt-start-minimized
87     playlistVisible      = false; // FIXME remove
88     input_name           = "";
89     i_bg_height          = 0;
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_keep_size = !var_InheritBool( p_intf, "qt-video-autoresize" );
111
112     /* Are we in the enhanced always-video mode or not ? */
113     i_visualmode = var_InheritInteger( 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
126     /**
127      * Retrieve saved sizes for main window
128      *   mainBasedSize = based window size for normal mode
129      *                  (no video, no background)
130      *   mainVideoSize = window size with video (all modes)
131      **/
132     mainBasedSize = settings->value( "mainBasedSize", QSize( 350, 120 ) ).toSize();
133     mainVideoSize = settings->value( "mainVideoSize", QSize( 400, 300 ) ).toSize();
134
135
136     /**************
137      * Status Bar *
138      **************/
139     createStatusBar();
140
141     /**************************
142      *  UI and Widgets design
143      **************************/
144     setVLCWindowsTitle();
145     createMainWidget( settings );
146
147     /************
148      * Menu Bar *
149      ************/
150     QVLCMenu::createMenuBar( this, p_intf );
151     CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
152              this, destroyPopupMenu() );
153
154     /*********************************
155      * Create the Systray Management *
156      *********************************/
157     initSystray();
158
159     /********************
160      * Input Manager    *
161      ********************/
162     MainInputManager::getInstance( p_intf );
163
164 #ifdef WIN32
165     himl = NULL;
166     p_taskbl = NULL;
167     taskbar_wmsg = RegisterWindowMessage("TaskbarButtonCreated");
168 #endif
169
170     /************************************************************
171      * Connect the input manager to the GUI elements it manages *
172      ************************************************************/
173     /**
174      * Connects on nameChanged()
175      * Those connects are different because options can impeach them to trigger.
176      **/
177     /* Main Interface statusbar */
178     CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
179              this, setName( const QString& ) );
180     /* and systray */
181 #ifndef HAVE_MAEMO
182     if( sysTray )
183     {
184         CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
185                  this, updateSystrayTooltipName( const QString& ) );
186     }
187 #endif
188     /* and title of the Main Interface*/
189     if( var_InheritBool( p_intf, "qt-name-in-title" ) )
190     {
191         CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
192                  this, setVLCWindowsTitle( const QString& ) );
193     }
194
195     /**
196      * CONNECTS on PLAY_STATUS
197      **/
198     /* Status on the systray */
199 #ifndef HAVE_MAEMO
200     if( sysTray )
201     {
202         CONNECT( THEMIM->getIM(), statusChanged( int ),
203                  this, updateSystrayTooltipStatus( int ) );
204     }
205 #endif
206
207     /* END CONNECTS ON IM */
208
209     /* VideoWidget connects for asynchronous calls */
210     connect( this, SIGNAL(askGetVideo(WId*,int*,int*,unsigned*,unsigned *)),
211              this, SLOT(getVideoSlot(WId*,int*,int*,unsigned*,unsigned*)),
212              Qt::BlockingQueuedConnection );
213     connect( this, SIGNAL(askReleaseVideo( void )),
214              this, SLOT(releaseVideoSlot( void )),
215              Qt::BlockingQueuedConnection );
216
217     if( videoWidget )
218     {
219         CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
220                  videoWidget, SetSizing( unsigned int, unsigned int ) );
221         CONNECT( videoWidget, sizeChanged( int, int ),
222                  this, resizeStack( int,  int ) );
223         CONNECT( this, askVideoSetFullScreen( bool ),
224                  videoWidget, SetFullScreen( bool ) );
225         CONNECT( videoWidget, keyPressed( QKeyEvent * ),
226                  this, handleKeyPress( QKeyEvent * ) );
227     }
228
229     CONNECT( this, askUpdate(), this, doComponentsUpdate() );
230     CONNECT( THEDP, toolBarConfUpdated(), this, recreateToolbars() );
231
232     /* Enable the popup menu in the MI */
233     setContextMenuPolicy( Qt::CustomContextMenu );
234     CONNECT( this, customContextMenuRequested( const QPoint& ),
235              this, popupMenu( const QPoint& ) );
236
237     /** END of CONNECTS**/
238
239
240     /************
241      * Callbacks
242      ************/
243     var_AddCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );
244
245     /* Register callback for the intf-popupmenu variable */
246     var_AddCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
247
248     /**** FINAL SIZING and placement of interface */
249     settings->beginGroup( "MainWindow" );
250     QVLCTools::restoreWidgetPosition( settings, this, QSize(400, 100) );
251
252     /* resize to previously saved main window size if appicable */
253     //FIXME remove.
254     if( b_keep_size )
255     {
256        if( i_visualmode )
257            resize( mainVideoSize );
258        else
259            resize( mainBasedSize );
260     }
261
262     /* Playlist */
263     int i_plVis = settings->value( "playlist-visible", 0 ).toInt();
264
265     settings->endGroup();
266
267     if( i_plVis ) togglePlaylist();
268
269     /* Final sizing and showing */
270     setVisible( !b_hideAfterCreation );
271
272     setMinimumWidth( __MAX( controls->sizeHint().width(),
273                             menuBar()->sizeHint().width() ) + 30 );
274
275     /* Switch to minimal view if needed, must be called after the show() */
276     if( i_visualmode )
277         toggleMinimalView( true );
278 }
279
280 MainInterface::~MainInterface()
281 {
282     /* Unsure we hide the videoWidget before destroying it */
283     if( stackCentralOldWidget == playlistWidget )
284         showBg();
285
286     /* Save playlist state */
287     if( playlistWidget )
288     {
289         if( !isPlDocked() )
290             QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
291
292         delete playlistWidget;
293     }
294
295 #ifdef WIN32
296     if( himl )
297         ImageList_Destroy( himl );
298     if(p_taskbl)
299         p_taskbl->vt->Release(p_taskbl);
300     CoUninitialize();
301 #endif
302
303     /* Be sure to kill the actionsManager... FIXME */
304     ActionsManager::killInstance();
305
306     /* Idem, FIXME */
307     ExtensionsManager::killInstance();
308
309     /* Delete the FSC controller */
310     delete fullscreenControls;
311
312     /* Save states */
313     settings->beginGroup( "MainWindow" );
314     settings->setValue( "pl-dock-status", b_plDocked );
315     settings->setValue( "playlist-visible", (int)playlistVisible );
316     settings->setValue( "adv-controls",
317                         getControlsVisibilityStatus() & CONTROLS_ADVANCED );
318
319     settings->setValue( "mainBasedSize", mainBasedSize );
320     settings->setValue( "mainVideoSize", mainVideoSize );
321
322     settings->setValue( "backgroundSize", bgWidget->size() );
323
324     /* Save this size */
325     QVLCTools::saveWidgetPosition(settings, this);
326     settings->endGroup();
327
328     delete statusBar();
329
330     /* Unregister callbacks */
331     var_DelCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );
332     var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
333
334     p_intf->p_sys->p_mi = NULL;
335 }
336
337 /*****************************
338  *   Main UI handling        *
339  *****************************/
340 void MainInterface::recreateToolbars()
341 {
342     // FIXME: do the same for the FSC
343     //msg_Dbg( p_intf, "Recreating the toolbars" );
344     settings->beginGroup( "MainWindow" );
345     delete controls;
346     delete inputC;
347
348     controls = new ControlsWidget( p_intf, false, this ); /* FIXME */
349     CONNECT( controls, advancedControlsToggled( bool ),
350              this, doComponentsUpdate() );
351     CONNECT( controls, sizeChanged(),
352              this, doComponentsUpdate() );
353
354     inputC = new InputControlsWidget( p_intf, this );
355
356     mainLayout->insertWidget( 2, inputC );
357     mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
358                               controls );
359     settings->endGroup();
360 }
361
362 void MainInterface::createMainWidget( QSettings *settings )
363 {
364     /* Create the main Widget and the mainLayout */
365     QWidget *main = new QWidget;
366     setCentralWidget( main );
367     mainLayout = new QVBoxLayout( main );
368     main->setContentsMargins( 0, 0, 0, 0 );
369     mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
370
371     /* */
372     stackCentralW = new QStackedWidget( main );
373
374     /* Bg Cone */
375     bgWidget = new BackgroundWidget( p_intf );
376     stackCentralW->addWidget( bgWidget );
377
378     /* And video Outputs */
379     if( b_videoEmbedded )
380     {
381         videoWidget = new VideoWidget( p_intf );
382         stackCentralW->addWidget( videoWidget );
383     }
384     mainLayout->insertWidget( 1, stackCentralW );
385
386     /* Create the CONTROLS Widget */
387     controls = new ControlsWidget( p_intf,
388                    settings->value( "adv-controls", false ).toBool(), this );
389     CONNECT( controls, advancedControlsToggled( bool ),
390              this, doComponentsUpdate() );
391     CONNECT( controls, sizeChanged(),
392              this, doComponentsUpdate() );
393     inputC = new InputControlsWidget( p_intf, this );
394
395     mainLayout->insertWidget( 2, inputC );
396     mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
397                               controls );
398
399     /* Visualisation, disabled for now, they SUCK */
400     #if 0
401     visualSelector = new VisualSelector( p_intf );
402     mainLayout->insertWidget( 0, visualSelector );
403     visualSelector->hide();
404     #endif
405
406     getSettings()->endGroup();
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
459     /* and adding those */
460     statusBarr->addWidget( nameLabel, 8 );
461     statusBarr->addPermanentWidget( speedLabel, 0 );
462     statusBarr->addPermanentWidget( timeLabel, 0 );
463
464     /* timeLabel behaviour:
465        - double clicking opens the goto time dialog
466        - right-clicking and clicking just toggle between remaining and
467          elapsed time.*/
468     CONNECT( timeLabel, timeLabelDoubleClicked(), THEDP, gotoTimeDialog() );
469
470     CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
471              this, showCryptedLabel( bool ) );
472
473     CONNECT( THEMIM->getIM(), seekRequested( float ),
474              timeLabel, setDisplayPosition( float ) );
475 }
476
477 /**********************************************************************
478  * Handling of sizing of the components
479  **********************************************************************/
480
481 /* This function is probably wrong, but we don't have many many choices...
482    Since we can't know from the playlist Widget if we are inside a dock or not,
483    because the playlist Widget can be called by THEDP, as a separate windows for
484    the skins.
485    Maybe the other solution is to redefine the sizeHint() of the playlist and
486    ask _parent->isFloating()...
487    If you think this would be better, please FIXME it...
488 */
489 #if 0
490
491 QSize MainInterface::sizeHint() const
492 {
493 #if 0
494     if( b_keep_size )
495     {
496         if( i_visualmode )
497         {
498                 return mainVideoSize;
499         }
500         else
501         {
502             if( VISIBLE( bgWidget) ||
503                 ( videoIsActive && videoWidget->isVisible() )
504               )
505                 return mainVideoSize;
506             else
507                 return mainBasedSize;
508         }
509     }
510 #endif
511
512     int nwidth  = __MAX( controls->sizeHint().width(),
513                          menuBar()->sizeHint().width() );
514
515     int nheight = controls->isVisible() ?
516                   controls->size().height()
517                   + inputC->size().height()
518                   + menuBar()->size().height()
519                   + statusBar()->size().height()
520                   : 0 ;
521
522   /*  if( stackCentralW->isVisible() )
523     {
524         nheight += stackCentralW->height();
525         nwidth  = __MAX( nwidth, stackCentralW->width() );
526     }*/
527
528 /*    if( VISIBLE( bgWidget ) )
529     {
530         msg_Warn( p_intf, "Hello here" );
531         if( i_bg_height )
532             nheight += i_bg_height;
533         else
534             nheight += bgWidget->size().height();
535         nwidth  = __MAX( nwidth, bgWidget->size().width() );
536     }
537     else if( videoIsActive && videoWidget->isVisible() )
538     {
539         msg_Warn( p_intf, "Hello there" );
540         nheight += videoWidget->sizeHint().height();
541         nwidth  = __MAX( nwidth, videoWidget->sizeHint().width() );
542     }*/
543 #if 0
544     if( !dockPL->isFloating() && dockPL->isVisible() && dockPL->widget()  )
545     {
546         nheight += dockPL->size().height();
547         nwidth = __MAX( nwidth, dockPL->size().width() );
548         msg_Warn( p_intf, "3 %i %i", nheight, nwidth );
549     }
550 #endif
551     return QSize( nwidth, nheight );
552 }
553 #endif
554
555 /* Video widget cannot do this synchronously as it runs in another thread */
556 /* Well, could it, actually ? Probably dangerous ... */
557
558 /* This function is called:
559    - toggling of minimal View
560    - through askUpdate() by Vout thread request video and resize video (zoom)
561    - Advanced buttons toggled
562  */
563 void MainInterface::doComponentsUpdate()
564 {
565 #if 0
566     if( isFullScreen() || isMaximized() ) return;
567
568 //    msg_Warn( p_intf, "Updating the geometry" );
569     /* Here we resize to sizeHint() and not adjustsize because we want
570        the videoWidget to be exactly the correctSize */
571
572 #ifdef DEBUG_INTF
573     debug();
574 #endif
575     /* This is WRONG, but I believe there is a Qt bug here */
576     setMinimumSize( 0, 0 );
577     //resize( sizeHint() );
578
579     //adjustSize() ; /* This is not needed, but might help in the future */
580 #endif
581 }
582
583 void MainInterface::debug()
584 {
585 #ifdef DEBUG_INTF
586     msg_Dbg( p_intf, "Stack Size: %i - %i", stackCentralW->size().height(), size().width() );
587     if( videoWidget )
588         msg_Dbg( p_intf, "Stack Size: %i - %i",
589                  videoWidget->size().height(),
590                  videoWidget->size().width() );
591     else
592         msg_Dbg( p_intf, "no embedded video" );
593
594     msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
595     msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
596     msg_Dbg( p_intf, "maximumsize: %i - %i", maximumSize().height(), maximumSize().width() );
597     msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
598
599     msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
600     msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
601     msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
602     msg_Dbg( p_intf, "bg Size: %i - %i", bgWidget->size().height(), bgWidget->size().width() );
603
604     /*if( videoWidget && videoWidget->isVisible() )
605     {
606         msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
607         msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
608     }*/
609 #endif
610 }
611
612 inline void MainInterface::showVideo() { showTab( videoWidget ); }
613 inline void MainInterface::showBg() { showTab( bgWidget ); }
614
615 inline void MainInterface::showTab( QWidget *widget )
616 {
617 #ifdef DEBUG_INTF
618     msg_Warn( p_intf, "Old stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
619 #endif
620     stackCentralOldWidget = stackCentralW->currentWidget();
621     stackCentralW->setCurrentWidget( widget );
622
623 #ifdef DEBUG_INTF
624     msg_Warn( p_intf, "State change %i",  stackCentralW->currentIndex() );
625     msg_Warn( p_intf, "New stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
626 #endif
627 }
628
629 inline void MainInterface::restoreStackOldWidget()
630 {
631 #ifdef DEBUG_INTF
632     msg_Warn( p_intf, "New stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
633 #endif
634     QWidget *wTemp = stackCentralW->currentWidget();
635
636     stackCentralW->setCurrentWidget( stackCentralOldWidget );
637
638     stackCentralOldWidget = wTemp;
639 #ifdef DEBUG_INTF
640     msg_Warn( p_intf, "Debug %i %i",stackCentralW->indexOf( wTemp ), stackCentralW->indexOf( stackCentralW->currentWidget() ) );
641 #endif
642 }
643
644 void MainInterface::destroyPopupMenu()
645 {
646     QVLCMenu::PopupMenu( p_intf, false );
647 }
648
649 void MainInterface::popupMenu( const QPoint &p )
650 {
651     /* FIXME
652      * Ow, that's ugly: don't show the popup menu if cursor over
653      * the main menu bar or the status bar */
654     if( !childAt( p ) || ( ( childAt( p ) != menuBar() )
655                         && ( childAt( p )->parentWidget() != statusBar() ) ) )
656         QVLCMenu::PopupMenu( p_intf, true );
657 }
658
659 void MainInterface::toggleFSC()
660 {
661    if( !fullscreenControls ) return;
662
663    IMEvent *eShow = new IMEvent( FullscreenControlToggle_Type, 0 );
664    QApplication::postEvent( fullscreenControls, eShow );
665 }
666
667 /****************************************************************************
668  * Video Handling
669  ****************************************************************************/
670
671 /* This event is used to deal with the fullscreen and always on top
672    issue conflict (bug in wx) */
673 class SetVideoOnTopQtEvent : public QEvent
674 {
675 public:
676     SetVideoOnTopQtEvent( bool _onTop ) :
677       QEvent( (QEvent::Type)SetVideoOnTopEvent_Type ), onTop( _onTop)
678     {}
679
680     bool OnTop() const { return onTop; }
681
682 private:
683     bool onTop;
684 };
685
686 /**
687  * NOTE:
688  * You must not change the state of this object or other Qt4 UI objects,
689  * from the video output thread - only from the Qt4 UI main loop thread.
690  * All window provider queries must be handled through signals or events.
691  * That's why we have all those emit statements...
692  */
693 WId MainInterface::getVideo( int *pi_x, int *pi_y,
694                              unsigned int *pi_width, unsigned int *pi_height )
695 {
696     if( !videoWidget )
697         return 0;
698
699     /* This is a blocking call signal. Results are returned through pointers.
700      * Beware of deadlocks! */
701     WId id;
702     emit askGetVideo( &id, pi_x, pi_y, pi_width, pi_height );
703     return id;
704 }
705
706 void MainInterface::getVideoSlot( WId *p_id, int *pi_x, int *pi_y,
707                                   unsigned *pi_width, unsigned *pi_height )
708 {
709     /* Request the videoWidget */
710     WId ret = videoWidget->request( pi_x, pi_y,
711                                     pi_width, pi_height, b_keep_size );
712     *p_id = ret;
713     if( ret ) /* The videoWidget is available */
714     {
715         /* ask videoWidget to show */
716         videoWidget->SetSizing( *pi_width, *pi_height );
717
718         /* Consider the video active now */
719         showVideo();
720     }
721 }
722
723
724
725 /* Asynchronous call from the WindowClose function */
726 void MainInterface::releaseVideo( void )
727 {
728     emit askReleaseVideo( );
729 }
730
731 /* Function that is CONNECTED to the previous emit */
732 void MainInterface::releaseVideoSlot( void )
733 {
734     videoWidget->release( );
735
736     restoreStackOldWidget();
737
738     /* We don't want to have a blank video to popup */
739     stackCentralOldWidget = bgWidget;
740
741     /* Try to resize, except when you are in Fullscreen mode */
742 //    doComponentsUpdate();
743 }
744
745 /* Asynchronous call from WindowControl function */
746 int MainInterface::controlVideo( int i_query, va_list args )
747 {
748     switch( i_query )
749     {
750     case VOUT_WINDOW_SET_SIZE:
751     {
752         unsigned int i_width  = va_arg( args, unsigned int );
753         unsigned int i_height = va_arg( args, unsigned int );
754         emit askVideoToResize( i_width, i_height );
755         return VLC_SUCCESS;
756     }
757     case VOUT_WINDOW_SET_STATE:
758     {
759         unsigned i_arg = va_arg( args, unsigned );
760         unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
761         QApplication::postEvent( this, new SetVideoOnTopQtEvent( on_top ) );
762         return VLC_SUCCESS;
763     }
764     case VOUT_WINDOW_SET_FULLSCREEN:
765     {
766         bool b_fs = va_arg( args, int );
767         emit askVideoSetFullScreen( b_fs );
768         return VLC_SUCCESS;
769     }
770     default:
771         msg_Warn( p_intf, "unsupported control query" );
772         return VLC_EGENERIC;
773     }
774 }
775
776 /*****************************************************************************
777  * Playlist, Visualisation and Menus handling
778  *****************************************************************************/
779 /**
780  * Toggle the playlist widget or dialog
781  **/
782 void MainInterface::createPlaylist()
783 {
784     playlistWidget = new PlaylistWidget( p_intf, this );
785
786     if( !b_plDocked )
787     {
788         playlistWidget->setWindowFlags( Qt::Window );
789
790         /* This will restore the geometry but will not work for position,
791            because of parenting */
792         QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
793                 playlistWidget, QSize( 600, 300 ) );
794     }
795     else
796     {
797         stackCentralW->addWidget( playlistWidget );
798     }
799 }
800
801 void MainInterface::togglePlaylist()
802 {
803     if( !playlistWidget )
804         createPlaylist();
805
806     if( b_plDocked )
807     {
808         /* Playlist is not visible, show it */
809         if( stackCentralW->currentWidget() != playlistWidget )
810         {
811             playlistWidget->forceShow();
812             showTab( playlistWidget );
813         }
814         else /* Hide it! */
815         {
816             restoreStackOldWidget();
817             stackCentralW->updateGeometry();
818             // HACK: So it doesn't limit the stackWidget minimumSize
819             playlistWidget->forceHide();
820         }
821         playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
822     }
823     else
824     {
825         playlistWidget->setWindowFlags( Qt::Window );
826         playlistVisible = !playlistVisible;
827         playlistWidget->setVisible( playlistVisible );
828     }
829     debug();
830 }
831
832 void MainInterface::dockPlaylist( bool p_docked )
833 {
834     if( b_plDocked == p_docked ) return;
835     b_plDocked = p_docked;
836
837     if( !playlistWidget ) return; /* Playlist wasn't created yet */
838     if( !p_docked )
839     {
840         stackCentralW->removeWidget( playlistWidget );
841         playlistWidget->setWindowFlags( Qt::Window );
842         QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
843                 playlistWidget, QSize( 600, 300 ) );
844         playlistWidget->show();
845         restoreStackOldWidget();
846     }
847     else
848     {
849         playlistWidget->setWindowFlags( Qt::Widget ); // Probably a Qt bug here
850         // It would be logical that QStackWidget::addWidget reset the flags...
851         stackCentralW->addWidget( playlistWidget );
852         stackCentralW->setCurrentWidget( playlistWidget );
853     }
854 }
855
856 /*
857   If b_switch is false, then we are normalView
858  */
859 void MainInterface::toggleMinimalView( bool b_switch )
860 {
861     if( i_visualmode == 0 )
862     { /* NORMAL MODE then */
863         if( !videoWidget || stackCentralW->currentWidget() != videoWidget )
864         {
865             showBg();
866         }
867         else
868         {
869             /* If video is visible, then toggle the status of bgWidget */
870             //FIXME
871             //bgWasVisible = !bgWasVisible;
872             /* if( stackCentralOldState == BACK G_TAB )
873                 stackCentralOldState = HID DEN_TAB;
874             else
875                 stackCentralOldState = BACK G_TAB;
876
877                 */
878         }
879     }
880
881     i_bg_height = stackCentralW->height();
882
883     menuBar()->setVisible( !b_switch );
884     controls->setVisible( !b_switch );
885     statusBar()->setVisible( !b_switch );
886     inputC->setVisible( !b_switch );
887
888     doComponentsUpdate();
889
890     emit minimalViewToggled( b_switch );
891 }
892
893 /* toggling advanced controls buttons */
894 void MainInterface::toggleAdvanced()
895 {
896     controls->toggleAdvanced();
897 //    if( fullscreenControls ) fullscreenControls->toggleAdvanced();
898 }
899
900 /* Get the visibility status of the controls (hidden or not, advanced or not) */
901 int MainInterface::getControlsVisibilityStatus()
902 {
903     return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
904                 + CONTROLS_ADVANCED * controls->b_advancedVisible );
905 }
906
907 #if 0
908 void MainInterface::visual()
909 {
910     if( !VISIBLE( visualSelector) )
911     {
912         visualSelector->show();
913         if( !THEMIM->getIM()->hasVideo() )
914         {
915             /* Show the background widget */
916         }
917         visualSelectorEnabled = true;
918     }
919     else
920     {
921         /* Stop any currently running visualization */
922         visualSelector->hide();
923         visualSelectorEnabled = false;
924     }
925     doComponentsUpdate();
926 }
927 #endif
928
929 /************************************************************************
930  * Other stuff
931  ************************************************************************/
932 void MainInterface::setName( const QString& name )
933 {
934     input_name = name; /* store it for the QSystray use */
935     /* Display it in the status bar, but also as a Tooltip in case it doesn't
936        fit in the label */
937     nameLabel->setText( " " + name + " " );
938     nameLabel->setToolTip( " " + name +" " );
939 }
940
941 /**
942  * Give the decorations of the Main Window a correct Name.
943  * If nothing is given, set it to VLC...
944  **/
945 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
946 {
947     if( aTitle.isEmpty() )
948     {
949         setWindowTitle( qtr( "VLC media player" ) );
950     }
951     else
952     {
953         setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
954     }
955 }
956
957 void MainInterface::showCryptedLabel( bool b_show )
958 {
959     if( cryptedLabel == NULL )
960     {
961         cryptedLabel = new QLabel;
962         // The lock icon is not the right one for DRM protection/scrambled.
963         //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
964         cryptedLabel->setText( "DRM" );
965         statusBar()->addWidget( cryptedLabel );
966     }
967
968     cryptedLabel->setVisible( b_show );
969 }
970
971 void MainInterface::showBuffering( float f_cache )
972 {
973     QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
974     statusBar()->showMessage( amount, 1000 );
975 }
976
977 /*****************************************************************************
978  * Systray Icon and Systray Menu
979  *****************************************************************************/
980 #ifndef HAVE_MAEMO
981 /**
982  * Create a SystemTray icon and a menu that would go with it.
983  * Connects to a click handler on the icon.
984  **/
985 void MainInterface::createSystray()
986 {
987     QIcon iconVLC;
988     if( QDate::currentDate().dayOfYear() >= 354 )
989         iconVLC =  QIcon( ":/logo/vlc128-christmas.png" );
990     else
991         iconVLC =  QIcon( ":/logo/vlc128.png" );
992     sysTray = new QSystemTrayIcon( iconVLC, this );
993     sysTray->setToolTip( qtr( "VLC media player" ));
994
995     systrayMenu = new QMenu( qtr( "VLC media player" ), this );
996     systrayMenu->setIcon( iconVLC );
997
998     QVLCMenu::updateSystrayMenu( this, p_intf, true );
999     sysTray->show();
1000
1001     CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
1002             this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
1003 }
1004
1005 /**
1006  * Updates the Systray Icon's menu and toggle the main interface
1007  */
1008 void MainInterface::toggleUpdateSystrayMenu()
1009 {
1010     /* If hidden, show it */
1011     if( isHidden() )
1012     {
1013         show();
1014         activateWindow();
1015     }
1016     else if( isMinimized() )
1017     {
1018         /* Minimized */
1019         showNormal();
1020         activateWindow();
1021     }
1022     else
1023     {
1024         /* Visible (possibly under other windows) */
1025 #ifdef WIN32
1026         /* check if any visible window is above vlc in the z-order,
1027          * but ignore the ones always on top
1028          * and the ones which can't be activated */
1029         WINDOWINFO wi;
1030         HWND hwnd;
1031         wi.cbSize = sizeof( WINDOWINFO );
1032         for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
1033                 hwnd && ( !IsWindowVisible( hwnd ) ||
1034                     ( GetWindowInfo( hwnd, &wi ) &&
1035                       (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
1036                 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
1037             if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
1038                 (wi.dwExStyle&WS_EX_TOPMOST) )
1039             {
1040                 hide();
1041             }
1042             else
1043             {
1044                 activateWindow();
1045             }
1046 #else
1047         hide();
1048 #endif
1049     }
1050     QVLCMenu::updateSystrayMenu( this, p_intf );
1051 }
1052
1053 void MainInterface::handleSystrayClick(
1054                                     QSystemTrayIcon::ActivationReason reason )
1055 {
1056     switch( reason )
1057     {
1058         case QSystemTrayIcon::Trigger:
1059         case QSystemTrayIcon::DoubleClick:
1060             toggleUpdateSystrayMenu();
1061             break;
1062         case QSystemTrayIcon::MiddleClick:
1063             sysTray->showMessage( qtr( "VLC media player" ),
1064                     qtr( "Control menu for the player" ),
1065                     QSystemTrayIcon::Information, 3000 );
1066             break;
1067         default:
1068             break;
1069     }
1070 }
1071
1072 /**
1073  * Updates the name of the systray Icon tooltip.
1074  * Doesn't check if the systray exists, check before you call it.
1075  **/
1076 void MainInterface::updateSystrayTooltipName( const QString& name )
1077 {
1078     if( name.isEmpty() )
1079     {
1080         sysTray->setToolTip( qtr( "VLC media player" ) );
1081     }
1082     else
1083     {
1084         sysTray->setToolTip( name );
1085         if( b_notificationEnabled && ( isHidden() || isMinimized() ) )
1086         {
1087             sysTray->showMessage( qtr( "VLC media player" ), name,
1088                     QSystemTrayIcon::NoIcon, 3000 );
1089         }
1090     }
1091
1092     QVLCMenu::updateSystrayMenu( this, p_intf );
1093 }
1094
1095 /**
1096  * Updates the status of the systray Icon tooltip.
1097  * Doesn't check if the systray exists, check before you call it.
1098  **/
1099 void MainInterface::updateSystrayTooltipStatus( int i_status )
1100 {
1101     switch( i_status )
1102     {
1103         case  0:
1104         case  END_S:
1105             {
1106                 sysTray->setToolTip( qtr( "VLC media player" ) );
1107                 break;
1108             }
1109         case PLAYING_S:
1110             {
1111                 sysTray->setToolTip( input_name );
1112                 break;
1113             }
1114         case PAUSE_S:
1115             {
1116                 sysTray->setToolTip( input_name + " - "
1117                         + qtr( "Paused") );
1118                 break;
1119             }
1120     }
1121     QVLCMenu::updateSystrayMenu( this, p_intf );
1122 }
1123 #endif
1124
1125 /************************************************************************
1126  * D&D Events
1127  ************************************************************************/
1128 void MainInterface::dropEvent(QDropEvent *event)
1129 {
1130     dropEventPlay( event, true );
1131 }
1132
1133 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play )
1134 {
1135     event->setDropAction( Qt::CopyAction );
1136     if( !event->possibleActions() & Qt::CopyAction )
1137         return;
1138
1139     const QMimeData *mimeData = event->mimeData();
1140
1141     /* D&D of a subtitles file, add it on the fly */
1142     if( mimeData->urls().size() == 1 && THEMIM->getIM()->hasInput() )
1143     {
1144         if( !input_AddSubtitle( THEMIM->getInput(),
1145                  qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1146                  true ) )
1147         {
1148             event->accept();
1149             return;
1150         }
1151     }
1152
1153     bool first = b_play;
1154     foreach( const QUrl &url, mimeData->urls() )
1155     {
1156         QString s = toNativeSeparators( url.toLocalFile() );
1157
1158         if( s.length() > 0 ) {
1159             char* psz_uri = make_URI( qtu(s) );
1160             playlist_Add( THEPL, psz_uri, NULL,
1161                           PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1162                           PLAYLIST_END, true, pl_Unlocked );
1163             free( psz_uri );
1164             first = false;
1165             RecentsMRL::getInstance( p_intf )->addRecent( s );
1166         }
1167     }
1168     event->accept();
1169 }
1170 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1171 {
1172      event->acceptProposedAction();
1173 }
1174 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1175 {
1176      event->acceptProposedAction();
1177 }
1178 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1179 {
1180      event->accept();
1181 }
1182
1183 /************************************************************************
1184  * Events stuff
1185  ************************************************************************/
1186 void MainInterface::customEvent( QEvent *event )
1187 {
1188 #if 0
1189     if( event->type() == PLDockEvent_Type )
1190     {
1191         PlaylistDialog::killInstance();
1192         playlistEmbeddedFlag = true;
1193         menuBar()->clear();
1194         QVLCMenu::createMenuBar(this, p_intf, true, visualSelectorEnabled);
1195         togglePlaylist();
1196     }
1197 #endif
1198     /*else */
1199     if ( event->type() == (int)SetVideoOnTopEvent_Type )
1200     {
1201         SetVideoOnTopQtEvent* p_event = (SetVideoOnTopQtEvent*)event;
1202         if( p_event->OnTop() )
1203             setWindowFlags( windowFlags() | Qt::WindowStaysOnTopHint );
1204         else
1205             setWindowFlags( windowFlags() & ~Qt::WindowStaysOnTopHint );
1206         show(); /* necessary to apply window flags */
1207     }
1208 }
1209
1210 void MainInterface::keyPressEvent( QKeyEvent *e )
1211 {
1212     handleKeyPress( e );
1213 }
1214
1215 void MainInterface::handleKeyPress( QKeyEvent *e )
1216 {
1217     if( ( e->modifiers() &  Qt::ControlModifier ) && ( e->key() == Qt::Key_H )
1218           && !menuBar()->isVisible() )
1219     {
1220         toggleMinimalView( false );
1221         e->accept();
1222     }
1223
1224     int i_vlck = qtEventToVLCKey( e );
1225     if( i_vlck > 0 )
1226     {
1227         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1228         e->accept();
1229     }
1230     else
1231         e->ignore();
1232 }
1233
1234 void MainInterface::resizeEvent( QResizeEvent * event )
1235 {
1236 #if 0
1237     if( b_keep_size )
1238     {
1239         if( i_visualmode )
1240         {
1241                 mainVideoSize = size();
1242         }
1243         else
1244         {
1245             if( VISIBLE( bgWidget) ||
1246                 ( videoIsActive && videoWidget->isVisible() )
1247               )
1248                 mainVideoSize = size();
1249             else
1250                 mainBasedSize = size();
1251         }
1252     }
1253 #endif
1254     QVLCMW::resizeEvent( event );
1255     msg_Dbg( p_intf, "Resize Event, height: %i", size().height() );
1256     debug();
1257 }
1258
1259 void MainInterface::wheelEvent( QWheelEvent *e )
1260 {
1261     int i_vlckey = qtWheelEventToVLCKey( e );
1262     var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1263     e->accept();
1264 }
1265
1266 void MainInterface::closeEvent( QCloseEvent *e )
1267 {
1268     e->accept();
1269     hide();
1270     THEDP->quit();
1271 }
1272
1273 void MainInterface::toggleFullScreen( void )
1274 {
1275     if( isFullScreen() )
1276     {
1277         showNormal();
1278         emit askUpdate(); // Needed if video was launched after the F11
1279         //FIXMe
1280         emit fullscreenInterfaceToggled( false );
1281     }
1282     else
1283     {
1284         showFullScreen();
1285         emit fullscreenInterfaceToggled( true );
1286     }
1287
1288 }
1289
1290 /*****************************************************************************
1291  * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1292  *  We don't show the menu directly here because we don't want the
1293  *  caller to block for a too long time.
1294  *****************************************************************************/
1295 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1296                         vlc_value_t old_val, vlc_value_t new_val, void *param )
1297 {
1298     intf_thread_t *p_intf = (intf_thread_t *)param;
1299
1300     if( p_intf->pf_show_dialog )
1301     {
1302         p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1303                                 new_val.b_bool, NULL );
1304     }
1305
1306     return VLC_SUCCESS;
1307 }
1308
1309 /*****************************************************************************
1310  * IntfShowCB: callback triggered by the intf-show libvlc variable.
1311  *****************************************************************************/
1312 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1313                        vlc_value_t old_val, vlc_value_t new_val, void *param )
1314 {
1315     intf_thread_t *p_intf = (intf_thread_t *)param;
1316     p_intf->p_sys->p_mi->toggleFSC();
1317
1318     /* Show event */
1319      return VLC_SUCCESS;
1320 }