1 /*****************************************************************************
2  * menus.cpp : Qt menus
3  *****************************************************************************
4  * Copyright © 2006-2011 the VideoLAN team
5  * $Id: f83bc232e96b9705777c6725ec4fc76de8c2d492 $
6  *
7  * Authors: Clément Stenac <zorglub@videolan.org>
8  *          Jean-Baptiste Kempf <jb@videolan.org>
9  *          Jean-Philippe André <jpeg@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
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25 
26 /** \todo
27  * - Remove static currentGroup
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33 
34 #include <vlc_common.h>
35 #include <vlc_intf_strings.h>
36 #include <vlc_vout.h>                             /* vout_thread_t */
37 #include <vlc_aout.h>                             /* audio_output_t */
38 
39 #include "menus.hpp"
40 
41 #include "main_interface.hpp"                     /* View modifications */
42 #include "dialogs_provider.hpp"                   /* Dialogs display */
43 #include "input_manager.hpp"                      /* Input Management */
44 #include "recents.hpp"                            /* Recent Items */
45 #include "actions_manager.hpp"                    /* Actions Management: play+volume */
46 #include "extensions_manager.hpp"                 /* Extensions menu */
47 #include "util/qmenuview.hpp"                     /* Simple Playlist menu */
48 #include "components/playlist/playlist_model.hpp" /* PLModel getter */
49 #include "components/playlist/standardpanel.hpp"  /* PLView getter */
50 #include "components/extended_panels.hpp"
51 
52 #include <QMenu>
53 #include <QMenuBar>
54 #include <QAction>
55 #include <QActionGroup>
56 #include <QSignalMapper>
57 #include <QStatusBar>
58 
59 /*
60   This file defines the main menus and the pop-up menu (right-click menu)
61   and the systray menu (in that order in the file)
62 
63   There are 4 menus that have to be rebuilt everytime there are called:
64   Audio, Video, Navigation, view
65   4 functions are building those menus: AudioMenu, VideoMenu, NavigMenu, View
66   and 3 functions associated are collecting the objects :
67   InputAutoMenuBuilder, AudioAutoMenuBuilder, VideoAutoMenuBuilder.
68 
69   A QSignalMapper decides when to rebuild those menus cf MenuFunc in the .hpp
70   Just before one of those menus are aboutToShow(), they are rebuild.
71   */
72 
73 enum
74 {
75     ITEM_NORMAL, /* not a checkbox, nor a radio */
76     ITEM_CHECK,  /* Checkbox */
77     ITEM_RADIO   /* Radiobox */
78 };
79 
80 static QActionGroup *currentGroup;
81 
82 QMenu *VLCMenuBar::recentsMenu = NULL;
83 QMenu *VLCMenuBar::audioDeviceMenu = NULL;
84 QMenu *VLCMenuBar::rendererMenu = NULL;
85 QActionGroup *VLCMenuBar::rendererGroup = NULL;
86 
87 /**
88  * @brief Add static entries to DP in menus
89  **/
addDPStaticEntry(QMenu * menu,const QString & text,const char * icon,const char * member,const char * shortcut=NULL,QAction::MenuRole role=QAction::NoRole)90 QAction *addDPStaticEntry( QMenu *menu,
91                        const QString& text,
92                        const char *icon,
93                        const char *member,
94                        const char *shortcut = NULL,
95                        QAction::MenuRole role = QAction::NoRole
96                        )
97 {
98     QAction *action = NULL;
99 #ifndef __APPLE__ /* We don't set icons in menus in MacOS X */
100     if( !EMPTY_STR( icon ) )
101     {
102         if( !EMPTY_STR( shortcut ) )
103             action = menu->addAction( QIcon( icon ), text, THEDP,
104                                       member, qtr( shortcut ) );
105         else
106             action = menu->addAction( QIcon( icon ), text, THEDP, member );
107     }
108     else
109 #endif
110     {
111         if( !EMPTY_STR( shortcut ) )
112             action = menu->addAction( text, THEDP, member, qtr( shortcut ) );
113         else
114             action = menu->addAction( text, THEDP, member );
115     }
116 #ifdef __APPLE__
117     action->setMenuRole( role );
118 #else
119     Q_UNUSED( role );
120 #endif
121     action->setData( VLCMenuBar::ACTION_STATIC );
122     return action;
123 }
124 
125 /**
126  * @brief Add static entries to MIM in menus
127  **/
addMIMStaticEntry(intf_thread_t * p_intf,QMenu * menu,const QString & text,const char * icon,const char * member,bool bStatic=false)128 QAction* addMIMStaticEntry( intf_thread_t *p_intf,
129                             QMenu *menu,
130                             const QString& text,
131                             const char *icon,
132                             const char *member,
133                             bool bStatic = false )
134 {
135     QAction *action;
136 #ifndef __APPLE__ /* We don't set icons in menus in MacOS X */
137     if( !EMPTY_STR( icon ) )
138     {
139         action = menu->addAction( text, THEMIM,  member );
140         action->setIcon( QIcon( icon ) );
141     }
142     else
143 #endif
144     {
145         action = menu->addAction( text, THEMIM, member );
146     }
147     action->setData( VLCMenuBar::ACTION_STATIC |
148                      ( bStatic ) ? VLCMenuBar::ACTION_ALWAYS_ENABLED
149                                  : VLCMenuBar::ACTION_NONE
150                    );
151     return action;
152 }
153 
154 /**
155  * @brief Enable all static entries of a menu, disable the others
156  * @param menu the menu in which the entries will be disabled
157  * @param enable if false, disable all entries
158  **/
EnableStaticEntries(QMenu * menu,bool enable=true)159 void VLCMenuBar::EnableStaticEntries( QMenu *menu, bool enable = true )
160 {
161     if( !menu ) return;
162 
163     QList< QAction* > actions = menu->actions();
164     for( int i = 0; i < actions.count(); ++i )
165     {
166         int actionflags = actions[i]->data().toInt();
167         if ( actionflags & ACTION_MANAGED )
168             actions[i]->setEnabled(
169                 ( actionflags & ACTION_ALWAYS_ENABLED )
170                 ||
171                 enable
172             );
173     }
174 }
175 
176 /**
177  * \return Number of static entries
178  **/
DeleteNonStaticEntries(QMenu * menu)179 inline int DeleteNonStaticEntries( QMenu *menu )
180 {
181     if( !menu ) return VLC_EGENERIC;
182 
183     int i_ret = 0;
184 
185     QList< QAction* > actions = menu->actions();
186     for( int i = 0; i < actions.count(); ++i )
187     {
188         if( actions[i]->data().toInt() & VLCMenuBar::ACTION_NO_CLEANUP )
189             i_ret++;
190         else
191             delete actions[i];
192     }
193     return i_ret;
194 }
195 
196 /**
197  * \return QAction associated to psz_var variable
198  **/
FindActionWithVar(QMenu * menu,const char * psz_var)199 static QAction * FindActionWithVar( QMenu *menu, const char *psz_var )
200 {
201     QList< QAction* > actions = menu->actions();
202     for( int i = 0; i < actions.count(); ++i )
203     {
204         if( actions[i]->data().toString() == psz_var )
205             return actions[i];
206     }
207     return NULL;
208 }
209 
210 /*****************************************************************************
211  * Definitions of variables for the dynamic menus
212  *****************************************************************************/
213 #define PUSH_OBJVAR(object,var) \
214     do { \
215         varnames.append(var); \
216         objects.append(VLC_OBJECT(object)); \
217     } while (0)
218 
219 #define PUSH_VAR(var) PUSH_OBJVAR(p_object, var)
220 #define PUSH_INPUTVAR(var) PUSH_OBJVAR(p_input, var)
221 #define PUSH_PLVAR(var) PUSH_OBJVAR(pl, var)
222 
InputAutoMenuBuilder(input_thread_t * p_input,QVector<vlc_object_t * > & objects,QVector<const char * > & varnames)223 static int InputAutoMenuBuilder( input_thread_t *p_input,
224         QVector<vlc_object_t *> &objects, QVector<const char *> &varnames )
225 {
226     PUSH_INPUTVAR( "bookmark" );
227     PUSH_INPUTVAR( "title" );
228     PUSH_INPUTVAR( "chapter" );
229     PUSH_INPUTVAR( "program" );
230 
231     return VLC_SUCCESS;
232 }
233 
VideoAutoMenuBuilder(playlist_t * pl,input_thread_t * p_input,QVector<vlc_object_t * > & objects,QVector<const char * > & varnames)234 static int VideoAutoMenuBuilder( playlist_t *pl, input_thread_t *p_input,
235         QVector<vlc_object_t *> &objects, QVector<const char *> &varnames )
236 {
237     vout_thread_t *p_object = p_input ? input_GetVout( p_input ) : NULL;
238 
239     PUSH_INPUTVAR( "video-es" );
240     PUSH_PLVAR( "fullscreen" );
241     PUSH_PLVAR( "video-wallpaper" );
242     PUSH_VAR( "video-snapshot" );
243     PUSH_VAR( "zoom" );
244     PUSH_VAR( "autoscale" );
245     PUSH_VAR( "aspect-ratio" );
246     PUSH_VAR( "crop" );
247     PUSH_VAR( "deinterlace" );
248     PUSH_VAR( "deinterlace-mode" );
249 
250     if( p_object )
251         vlc_object_release( p_object );
252     return VLC_SUCCESS;
253 }
254 
SubsAutoMenuBuilder(input_thread_t * p_input,QVector<vlc_object_t * > & objects,QVector<const char * > & varnames)255 static int SubsAutoMenuBuilder( input_thread_t *p_input,
256         QVector<vlc_object_t *> &objects, QVector<const char *> &varnames )
257 {
258     PUSH_INPUTVAR( "spu-es" );
259 
260     return VLC_SUCCESS;
261 }
262 
AudioAutoMenuBuilder(input_thread_t * p_input,QVector<vlc_object_t * > & objects,QVector<const char * > & varnames)263 static int AudioAutoMenuBuilder( input_thread_t *p_input,
264         QVector<vlc_object_t *> &objects, QVector<const char *> &varnames )
265 {
266     audio_output_t *p_object = p_input ? input_GetAout( p_input ) : NULL;
267 
268     PUSH_INPUTVAR( "audio-es" );
269     PUSH_VAR( "stereo-mode" );
270     PUSH_VAR( "visual" );
271 
272     if( p_object )
273         vlc_object_release( p_object );
274     return VLC_SUCCESS;
275 }
276 
277 /*****************************************************************************
278  * All normal menus
279  * Simple Code
280  *****************************************************************************/
281 
282 // Static menu
addMenuToMainbar(QMenu * func,QString title,QMenuBar * bar)283 static inline void addMenuToMainbar( QMenu *func, QString title, QMenuBar *bar ) {
284     func->setTitle( title );
285     bar->addMenu( func);
286 }
287 
288 // Dynamic menu
289 #define BAR_DADD( func, title, id ) { \
290     QMenu *_menu = func; _menu->setTitle( title ); bar->addMenu( _menu ); \
291     MenuFunc *f = new MenuFunc( _menu, id ); \
292     CONNECT( _menu, aboutToShow(), THEDP->menusUpdateMapper, map() ); \
293     THEDP->menusUpdateMapper->setMapping( _menu, f ); }
294 
295 // Add a simple action
addAction(QMenu * _menu,QVariant val,QString title)296 static inline void addAction( QMenu *_menu, QVariant val, QString title ) {
297     QAction *_action = new QAction( title, _menu );
298     _action->setData( val );
299     _menu->addAction( _action );
300 }
301 
302 // Add an action with a submenu
addActionWithSubmenu(QMenu * _menu,QVariant val,QString title)303 static inline QMenu *addActionWithSubmenu( QMenu *_menu, QVariant val, QString title ) {
304     QAction *_action = new QAction( title, _menu );
305     QMenu *_submenu = new QMenu( _menu );
306     _action->setData( val );
307     _action->setMenu( _submenu );
308     _menu->addAction( _action );
309     return _submenu;
310 }
311 
312 // Add an action that is a checkbox
addActionWithCheckbox(QMenu * _menu,QVariant val,QString title)313 static inline void addActionWithCheckbox( QMenu *_menu, QVariant val, QString title ) {
314     QAction *_action = new QAction( title, _menu );
315     _action->setData( val );
316     _action->setCheckable( true );
317     _menu->addAction( _action );
318 }
319 
320 /**
321  * Main Menu Bar Creation
322  **/
createMenuBar(MainInterface * mi,intf_thread_t * p_intf)323 void VLCMenuBar::createMenuBar( MainInterface *mi,
324                               intf_thread_t *p_intf )
325 {
326     /* QMainWindows->menuBar()
327        gives the QProcess::destroyed timeout issue on Cleanlooks style with
328        setDesktopAware set to false */
329     QMenuBar *bar = mi->menuBar();
330 
331     addMenuToMainbar( FileMenu( p_intf, bar, mi ), qtr( "&Media" ), bar );
332 
333     /* Dynamic menus, rebuilt before being showed */
334     BAR_DADD( NavigMenu( p_intf, bar ), qtr( "P&layback" ), 3 );
335     BAR_DADD( AudioMenu( p_intf, bar ), qtr( "&Audio" ), 1 );
336     BAR_DADD( VideoMenu( p_intf, bar ), qtr( "&Video" ), 2 );
337     BAR_DADD( SubtitleMenu( p_intf, bar ), qtr( "Subti&tle" ), 5 );
338 
339     addMenuToMainbar( ToolsMenu( p_intf, bar ), qtr( "Tool&s" ), bar );
340 
341     /* View menu, a bit different */
342     BAR_DADD( ViewMenu( p_intf, NULL, mi ), qtr( "V&iew" ), 4 );
343 
344     addMenuToMainbar( HelpMenu( bar ), qtr( "&Help" ), bar );
345 
346 }
347 
348 /**
349  * Media ( File ) Menu
350  * Opening, streaming and quit
351  **/
FileMenu(intf_thread_t * p_intf,QWidget * parent,MainInterface * mi)352 QMenu *VLCMenuBar::FileMenu( intf_thread_t *p_intf, QWidget *parent, MainInterface *mi )
353 {
354     QMenu *menu = new QMenu( parent );
355     QAction *action;
356 
357     addDPStaticEntry( menu, qtr( "Open &File..." ),
358         ":/type/file-asym.svg", SLOT( simpleOpenDialog() ), "Ctrl+O" );
359     addDPStaticEntry( menu, qtr( "&Open Multiple Files..." ),
360         ":/type/file-asym.svg", SLOT( openFileDialog() ), "Ctrl+Shift+O" );
361     addDPStaticEntry( menu, qtr( I_OP_OPDIR ),
362         ":/type/folder-grey.svg", SLOT( PLOpenDir() ), "Ctrl+F" );
363     addDPStaticEntry( menu, qtr( "Open &Disc..." ),
364         ":/type/disc.svg", SLOT( openDiscDialog() ), "Ctrl+D" );
365     addDPStaticEntry( menu, qtr( "Open &Network Stream..." ),
366         ":/type/network.svg", SLOT( openNetDialog() ), "Ctrl+N" );
367     addDPStaticEntry( menu, qtr( "Open &Capture Device..." ),
368         ":/type/capture-card.svg", SLOT( openCaptureDialog() ), "Ctrl+C" );
369 
370     addDPStaticEntry( menu, qtr( "Open &Location from clipboard" ),
371                       NULL, SLOT( openUrlDialog() ), "Ctrl+V" );
372 
373     if( !recentsMenu && var_InheritBool( p_intf, "qt-recentplay" ) )
374         recentsMenu = new QMenu( qtr( "Open &Recent Media" ) );
375 
376     if( recentsMenu )
377     {
378         updateRecents( p_intf );
379         menu->addMenu( recentsMenu );
380     }
381     menu->addSeparator();
382 
383     addDPStaticEntry( menu, qtr( I_PL_SAVE ), "", SLOT( savePlayingToPlaylist() ),
384         "Ctrl+Y" );
385 
386 #ifdef ENABLE_SOUT
387     addDPStaticEntry( menu, qtr( "Conve&rt / Save..." ), "",
388         SLOT( openAndTranscodingDialogs() ), "Ctrl+R" );
389     addDPStaticEntry( menu, qtr( "&Stream..." ),
390         ":/menu/stream.svg", SLOT( openAndStreamingDialogs() ), "Ctrl+S" );
391     menu->addSeparator();
392 #endif
393 
394     action = addMIMStaticEntry( p_intf, menu, qtr( "Quit at the end of playlist" ), "",
395                                SLOT( activatePlayQuit( bool ) ) );
396     action->setCheckable( true );
397     action->setChecked( THEMIM->getPlayExitState() );
398 
399     if( mi && mi->getSysTray() )
400     {
401         action = menu->addAction( qtr( "Close to systray"), mi,
402                                  SLOT( toggleUpdateSystrayMenu() ) );
403     }
404 
405     addDPStaticEntry( menu, qtr( "&Quit" ) ,
406         ":/menu/exit.svg", SLOT( quit() ), "Ctrl+Q" );
407     return menu;
408 }
409 
410 /**
411  * Tools, like Media Information, Preferences or Messages
412  **/
ToolsMenu(intf_thread_t * p_intf,QMenu * menu)413 QMenu *VLCMenuBar::ToolsMenu( intf_thread_t *p_intf, QMenu *menu )
414 {
415     addDPStaticEntry( menu, qtr( "&Effects and Filters"), ":/menu/settings.svg",
416             SLOT( extendedDialog() ), "Ctrl+E" );
417 
418     addDPStaticEntry( menu, qtr( "&Track Synchronization"), ":/menu/setting.svgs",
419             SLOT( synchroDialog() ), "" );
420 
421     addDPStaticEntry( menu, qtr( I_MENU_INFO ) , ":/menu/info.svg",
422         SLOT( mediaInfoDialog() ), "Ctrl+I" );
423     addDPStaticEntry( menu, qtr( I_MENU_CODECINFO ) ,
424         ":/menu/info.svg", SLOT( mediaCodecDialog() ), "Ctrl+J" );
425 
426 #ifdef ENABLE_VLM
427     addDPStaticEntry( menu, qtr( I_MENU_VLM ), "", SLOT( vlmDialog() ),
428         "Ctrl+Shift+W" );
429 #endif
430 
431     addDPStaticEntry( menu, qtr( "Program Guide" ), "", SLOT( epgDialog() ),
432         "" );
433 
434     addDPStaticEntry( menu, qtr( I_MENU_MSG ),
435         ":/menu/messages.svg", SLOT( messagesDialog() ), "Ctrl+M" );
436 
437     addDPStaticEntry( menu, qtr( "Plu&gins and extensions" ),
438         "", SLOT( pluginDialog() ) );
439     menu->addSeparator();
440 
441     if( !p_intf->p_sys->b_isDialogProvider )
442         addDPStaticEntry( menu, qtr( "Customi&ze Interface..." ),
443             ":/menu/preferences.svg", SLOT( toolbarDialog() ) );
444 
445     addDPStaticEntry( menu, qtr( "&Preferences" ),
446         ":/menu/preferences.svg", SLOT( prefsDialog() ), "Ctrl+P", QAction::PreferencesRole );
447 
448     return menu;
449 }
450 
451 /**
452  * View Menu
453  * Interface modification, load other interfaces, activate Extensions
454  * \param current, set to NULL for menu creation, else for menu update
455  **/
ViewMenu(intf_thread_t * p_intf,QMenu * current,MainInterface * _mi)456 QMenu *VLCMenuBar::ViewMenu( intf_thread_t *p_intf, QMenu *current, MainInterface *_mi )
457 {
458     QAction *action;
459     QMenu *menu;
460 
461     MainInterface *mi = _mi ? _mi : p_intf->p_sys->p_mi;
462     assert( mi );
463 
464     if( !current )
465     {
466         menu = new QMenu( qtr( "&View" ), mi );
467     }
468     else
469     {
470         menu = current;
471         //menu->clear();
472         //HACK menu->clear() does not delete submenus
473         QList<QAction*> actions = menu->actions();
474         foreach( QAction *a, actions )
475         {
476             QMenu *m = a->menu();
477             if( a->parent() == menu ) delete a;
478             else menu->removeAction( a );
479             if( m && m->parent() == menu ) delete m;
480         }
481     }
482 
483     menu->addAction(
484 #ifndef __APPLE__
485             QIcon( ":/menu/playlist_menu.svg" ),
486 #endif
487             qtr( "Play&list" ), mi,
488             SLOT( togglePlaylist() ), qtr( "Ctrl+L" ) );
489 
490     /* Docked Playlist */
491     action = menu->addAction( qtr( "Docked Playlist" ) );
492     action->setCheckable( true );
493     action->setChecked( mi->isPlDocked() );
494     CONNECT( action, triggered( bool ), mi, dockPlaylist( bool ) );
495 
496     if( mi->getPlaylistView() )
497         menu->addMenu( StandardPLPanel::viewSelectionMenu( mi->getPlaylistView() ) );
498 
499     menu->addSeparator();
500 
501     action = menu->addAction( qtr( "Always on &top" ) );
502     action->setCheckable( true );
503     action->setChecked( mi->isInterfaceAlwaysOnTop() );
504     CONNECT( action, triggered( bool ), mi, setInterfaceAlwaysOnTop( bool ) );
505 
506     menu->addSeparator();
507 
508     /* Minimal View */
509     action = menu->addAction( qtr( "Mi&nimal Interface" ) );
510     action->setShortcut( qtr( "Ctrl+H" ) );
511     action->setCheckable( true );
512     action->setChecked( (mi->getControlsVisibilityStatus()
513                          & MainInterface::CONTROLS_HIDDEN ) );
514 
515     CONNECT( action, triggered( bool ), mi, toggleMinimalView( bool ) );
516     CONNECT( mi, minimalViewToggled( bool ), action, setChecked( bool ) );
517 
518     /* FullScreen View */
519     action = menu->addAction( qtr( "&Fullscreen Interface" ), mi,
520             SLOT( toggleInterfaceFullScreen() ), QString( "F11" ) );
521     action->setCheckable( true );
522     action->setChecked( mi->isInterfaceFullScreen() );
523     CONNECT( mi, fullscreenInterfaceToggled( bool ),
524              action, setChecked( bool ) );
525 
526     /* Advanced Controls */
527     action = menu->addAction( qtr( "&Advanced Controls" ), mi,
528             SLOT( toggleAdvancedButtons() ) );
529     action->setCheckable( true );
530     if( mi->getControlsVisibilityStatus() & MainInterface::CONTROLS_ADVANCED )
531         action->setChecked( true );
532 
533     action = menu->addAction( qtr( "Status Bar" ) );
534     action->setCheckable( true );
535     action->setChecked( mi->statusBar()->isVisible() );
536     CONNECT( action, triggered( bool ), mi, setStatusBarVisibility( bool) );
537 #if 0 /* For Visualisations. Not yet working */
538     adv = menu->addAction( qtr( "Visualizations selector" ), mi,
539                            SLOT( visual() ) );
540     adv->setCheckable( true );
541     if( visual_selector_enabled ) adv->setChecked( true );
542 #endif
543 
544     menu->addSeparator();
545 
546     InterfacesMenu( p_intf, menu );
547     menu->addSeparator();
548 
549     /* Extensions */
550     ExtensionsMenu( p_intf, menu );
551 
552     return menu;
553 }
554 
555 /**
556  * Interface Sub-Menu, to list extras interface and skins
557  **/
InterfacesMenu(intf_thread_t * p_intf,QMenu * current)558 QMenu *VLCMenuBar::InterfacesMenu( intf_thread_t *p_intf, QMenu *current )
559 {
560     QVector<vlc_object_t *> objects;
561     QVector<const char *> varnames;
562     varnames.append( "intf-add" );
563     objects.append( VLC_OBJECT(p_intf) );
564 
565     return Populate( p_intf, current, varnames, objects );
566 }
567 
568 /**
569  * Extensions menu: populate the current menu with extensions
570  **/
ExtensionsMenu(intf_thread_t * p_intf,QMenu * extMenu)571 void VLCMenuBar::ExtensionsMenu( intf_thread_t *p_intf, QMenu *extMenu )
572 {
573     /* Get ExtensionsManager and load extensions if needed */
574     ExtensionsManager *extMgr = ExtensionsManager::getInstance( p_intf );
575 
576     if( !var_InheritBool( p_intf, "qt-autoload-extensions")
577         && !extMgr->isLoaded() )
578     {
579         return;
580     }
581 
582     if( !extMgr->isLoaded() && !extMgr->cannotLoad() )
583     {
584         extMgr->loadExtensions();
585     }
586 
587     /* Let the ExtensionsManager build itself the menu */
588     extMenu->addSeparator();
589     extMgr->menu( extMenu );
590 }
591 
VolumeEntries(intf_thread_t * p_intf,QMenu * current)592 static inline void VolumeEntries( intf_thread_t *p_intf, QMenu *current )
593 {
594     current->addSeparator();
595 
596     QAction *action = current->addAction( QIcon( ":/toolbar/volume-high.svg" ), qtr( "&Increase Volume" ),
597                 ActionsManager::getInstance( p_intf ), SLOT( AudioUp() ) );
598     action->setData( VLCMenuBar::ACTION_STATIC );
599     action = current->addAction( QIcon( ":/toolbar/volume-low.svg" ), qtr( "D&ecrease Volume" ),
600                 ActionsManager::getInstance( p_intf ), SLOT( AudioDown() ) );
601     action->setData( VLCMenuBar::ACTION_STATIC );
602     action = current->addAction( QIcon( ":/toolbar/volume-muted.svg" ), qtr( "&Mute" ),
603                 ActionsManager::getInstance( p_intf ), SLOT( toggleMuteAudio() ) );
604     action->setData( VLCMenuBar::ACTION_STATIC );
605 }
606 
607 /**
608  * Main Audio Menu
609  **/
AudioMenu(intf_thread_t * p_intf,QMenu * current)610 QMenu *VLCMenuBar::AudioMenu( intf_thread_t *p_intf, QMenu * current )
611 {
612     QVector<vlc_object_t *> objects;
613     QVector<const char *> varnames;
614     audio_output_t *p_aout;
615     input_thread_t *p_input;
616 
617     if (!audioDeviceMenu)
618         audioDeviceMenu = new QMenu( qtr( "Audio &Device" ) );
619 
620     if( current->isEmpty() )
621     {
622         addActionWithSubmenu( current, "audio-es", qtr( "Audio &Track" ) );
623         current->addMenu( audioDeviceMenu );
624         addActionWithSubmenu( current, "stereo-mode", qtr( "&Stereo Mode" ) );
625         current->addSeparator();
626 
627         addActionWithSubmenu( current, "visual", qtr( "&Visualizations" ) );
628         VolumeEntries( p_intf, current );
629     }
630 
631     p_input = THEMIM->getInput();
632     p_aout = THEMIM->getAout();
633     EnableStaticEntries( current, ( p_aout != NULL ) );
634     AudioAutoMenuBuilder( p_input, objects, varnames );
635     updateAudioDevice( p_intf, p_aout, audioDeviceMenu );
636     if( p_aout )
637     {
638         vlc_object_release( p_aout );
639     }
640 
641     return Populate( p_intf, current, varnames, objects );
642 }
643 
644 /* Subtitles */
SubtitleMenu(intf_thread_t * p_intf,QMenu * current,bool b_popup)645 QMenu *VLCMenuBar::SubtitleMenu( intf_thread_t *p_intf, QMenu *current, bool b_popup )
646 {
647     input_thread_t *p_input;
648     QVector<vlc_object_t *> objects;
649     QVector<const char *> varnames;
650 
651     if( current->isEmpty() || b_popup )
652     {
653         addDPStaticEntry( current, qtr( "Add &Subtitle File..." ), "",
654                 SLOT( loadSubtitlesFile() ) );
655         addActionWithSubmenu( current, "spu-es", qtr( "Sub &Track" ) );
656         current->addSeparator();
657     }
658 
659     p_input = THEMIM->getInput();
660     SubsAutoMenuBuilder( p_input, objects, varnames );
661 
662     return Populate( p_intf, current, varnames, objects );
663 }
664 
665 /**
666  * Main Video Menu
667  * Subtitles are part of Video.
668  **/
VideoMenu(intf_thread_t * p_intf,QMenu * current)669 QMenu *VLCMenuBar::VideoMenu( intf_thread_t *p_intf, QMenu *current )
670 {
671     input_thread_t *p_input;
672     QVector<vlc_object_t *> objects;
673     QVector<const char *> varnames;
674 
675     if( current->isEmpty() )
676     {
677         addActionWithSubmenu( current, "video-es", qtr( "Video &Track" ) );
678 
679         current->addSeparator();
680         /* Surface modifiers */
681         addActionWithCheckbox( current, "fullscreen", qtr( "&Fullscreen" ) );
682         addActionWithCheckbox( current, "autoscale", qtr( "Always Fit &Window" ) );
683         addActionWithCheckbox( current, "video-wallpaper", qtr( "Set as Wall&paper" ) );
684 
685         current->addSeparator();
686         /* Size modifiers */
687         addActionWithSubmenu( current, "zoom", qtr( "&Zoom" ) );
688         addActionWithSubmenu( current, "aspect-ratio", qtr( "&Aspect Ratio" ) );
689         addActionWithSubmenu( current, "crop", qtr( "&Crop" ) );
690 
691         current->addSeparator();
692         /* Rendering modifiers */
693         addActionWithSubmenu( current, "deinterlace", qtr( "&Deinterlace" ) );
694         addActionWithSubmenu( current, "deinterlace-mode", qtr( "&Deinterlace mode" ) );
695 
696         current->addSeparator();
697         /* Other actions */
698         addAction( current, "video-snapshot", qtr( "Take &Snapshot" ) );
699     }
700 
701     p_input = THEMIM->getInput();
702 
703     VideoAutoMenuBuilder( THEPL, p_input, objects, varnames );
704 
705     return Populate( p_intf, current, varnames, objects );
706 }
707 
708 /**
709  * Navigation Menu
710  * For DVD, MP4, MOV and other chapter based format
711  **/
NavigMenu(intf_thread_t * p_intf,QMenu * menu)712 QMenu *VLCMenuBar::NavigMenu( intf_thread_t *p_intf, QMenu *menu )
713 {
714     QAction *action;
715     QMenu *submenu;
716 
717     addActionWithSubmenu( menu, "title", qtr( "T&itle" ) );
718     submenu = addActionWithSubmenu( menu, "chapter", qtr( "&Chapter" ) );
719     submenu->setTearOffEnabled( true );
720     addActionWithSubmenu( menu, "program", qtr( "&Program" ) );
721 
722     submenu = new QMenu( qtr( I_MENU_BOOKMARK ), menu );
723     submenu->setTearOffEnabled( true );
724     addDPStaticEntry( submenu, qtr( "&Manage" ), "",
725                       SLOT( bookmarksDialog() ), "Ctrl+B" );
726     submenu->addSeparator();
727     action = menu->addMenu( submenu );
728     action->setData( "bookmark" );
729 
730     menu->addSeparator();
731 
732     if ( !rendererMenu )
733         rendererMenu = RendererMenu( p_intf );
734 
735     menu->addMenu( rendererMenu );
736     menu->addSeparator();
737 
738 
739     PopupMenuControlEntries( menu, p_intf );
740 
741     EnableStaticEntries( menu, ( THEMIM->getInput() != NULL ) );
742     return RebuildNavigMenu( p_intf, menu, true );
743 }
744 
RebuildNavigMenu(intf_thread_t * p_intf,QMenu * menu,bool b_keep)745 QMenu *VLCMenuBar::RebuildNavigMenu( intf_thread_t *p_intf, QMenu *menu, bool b_keep )
746 {
747     /* */
748     input_thread_t *p_object;
749     QVector<vlc_object_t *> objects;
750     QVector<const char *> varnames;
751 
752     /* Get the input and hold it */
753     p_object = THEMIM->getInput();
754 
755     InputAutoMenuBuilder( p_object, objects, varnames );
756 
757     /* Title and so on */
758     PUSH_VAR( "prev-title" );
759     PUSH_VAR( "next-title" );
760     PUSH_VAR( "prev-chapter" );
761     PUSH_VAR( "next-chapter" );
762 
763     /* */
764     EnableStaticEntries( menu, (p_object != NULL ) );
765     Populate( p_intf, menu, varnames, objects );
766 
767     /* Remove playback actions to recreate them */
768     if( !b_keep )
769     {
770         QList< QAction* > actions = menu->actions();
771         for( int i = 0; i < actions.count(); i++ )
772             if( actions[i]->data().toInt() & ACTION_DELETE_ON_REBUILD )
773                 delete actions[i];
774     }
775 
776     PopupMenuPlaylistEntries( menu, p_intf, p_object );
777 
778     return menu;
779 }
780 
781 /**
782  * Help/About Menu
783 **/
HelpMenu(QWidget * parent)784 QMenu *VLCMenuBar::HelpMenu( QWidget *parent )
785 {
786     QMenu *menu = new QMenu( parent );
787     addDPStaticEntry( menu, qtr( "&Help" ) ,
788         ":/menu/help.svg", SLOT( helpDialog() ), "F1" );
789 #ifdef UPDATE_CHECK
790     addDPStaticEntry( menu, qtr( "Check for &Updates..." ) , "",
791                       SLOT( updateDialog() ) );
792 #endif
793     menu->addSeparator();
794     addDPStaticEntry( menu, qtr( I_MENU_ABOUT ), ":/menu/info.svg",
795             SLOT( aboutDialog() ), "Shift+F1", QAction::AboutRole );
796     return menu;
797 }
798 
799 /*****************************************************************************
800  * Popup menus - Right Click menus                                           *
801  *****************************************************************************/
802 #define POPUP_BOILERPLATE \
803     QMenu* menu;  \
804     QVector<vlc_object_t *> objects; \
805     QVector<const char *> varnames; \
806     input_thread_t *p_input = THEMIM->getInput();
807 
808 #define CREATE_POPUP \
809     menu = new QMenu(); \
810     Populate( p_intf, menu, varnames, objects ); \
811     if( show ) \
812         menu->popup( QCursor::pos() ); \
813 
PopupMenuPlaylistEntries(QMenu * menu,intf_thread_t * p_intf,input_thread_t * p_input)814 void VLCMenuBar::PopupMenuPlaylistEntries( QMenu *menu,
815                                         intf_thread_t *p_intf,
816                                         input_thread_t *p_input )
817 {
818     QAction *action;
819 
820     /* Play or Pause action and icon */
821     if( !p_input || var_GetInteger( p_input, "state" ) != PLAYING_S )
822     {
823         action = menu->addAction( qtr( "&Play" ),
824                 ActionsManager::getInstance( p_intf ), SLOT( play() ) );
825 #ifndef __APPLE__ /* No icons in menus in Mac */
826         action->setIcon( QIcon( ":/toolbar/play_b.svg" ) );
827 #endif
828     }
829     else
830     {
831         action = addMIMStaticEntry( p_intf, menu, qtr( "Pause" ),
832                 ":/toolbar/pause_b.svg", SLOT( togglePlayPause() ) );
833     }
834     action->setData( ACTION_DELETE_ON_REBUILD );
835 
836     /* Stop */
837     action = addMIMStaticEntry( p_intf, menu, qtr( "&Stop" ),
838             ":/toolbar/stop_b.svg", SLOT( stop() ), true );
839     if( !p_input )
840         action->setEnabled( false );
841     action->setData( ACTION_DELETE_ON_REBUILD );
842 
843     /* Next / Previous */
844     bool bPlaylistEmpty = THEMIM->hasEmptyPlaylist();
845     action = addMIMStaticEntry( p_intf, menu, qtr( "Pre&vious" ),
846             ":/toolbar/previous_b.svg", SLOT( prev() ), true );
847     action->setEnabled( !bPlaylistEmpty );
848     action->setData( ACTION_NO_CLEANUP + ACTION_DELETE_ON_REBUILD );
849     CONNECT( THEMIM, playlistNotEmpty(bool), action, setEnabled(bool) );
850 
851     action = addMIMStaticEntry( p_intf, menu, qtr( "Ne&xt" ),
852             ":/toolbar/next_b.svg", SLOT( next() ), true );
853     action->setEnabled( !bPlaylistEmpty );
854     action->setData( ACTION_NO_CLEANUP + ACTION_DELETE_ON_REBUILD );
855     CONNECT( THEMIM, playlistNotEmpty(bool), action, setEnabled(bool) );
856 
857     action = menu->addAction( qtr( "Record" ), THEAM, SLOT( record() ) );
858     action->setIcon( QIcon( ":/toolbar/record.svg" ) );
859     if( !p_input )
860         action->setEnabled( false );
861     action->setData( ACTION_NO_CLEANUP + ACTION_DELETE_ON_REBUILD );
862     menu->addSeparator();
863 }
864 
PopupMenuControlEntries(QMenu * menu,intf_thread_t * p_intf,bool b_normal)865 void VLCMenuBar::PopupMenuControlEntries( QMenu *menu, intf_thread_t *p_intf,
866                                         bool b_normal )
867 {
868     QAction *action;
869     QMenu *rateMenu = new QMenu( qtr( "Sp&eed" ), menu );
870     rateMenu->setTearOffEnabled( true );
871 
872     if( b_normal )
873     {
874         /* Faster/Slower */
875         action = rateMenu->addAction( qtr( "&Faster" ), THEMIM->getIM(),
876                                   SLOT( faster() ) );
877 #ifndef __APPLE__ /* No icons in menus in Mac */
878         action->setIcon( QIcon( ":/toolbar/faster2.svg") );
879 #endif
880         action->setData( ACTION_STATIC );
881     }
882 
883     action = rateMenu->addAction( QIcon( ":/toolbar/faster2.svg" ), qtr( "Faster (fine)" ), THEMIM->getIM(),
884                               SLOT( littlefaster() ) );
885     action->setData( ACTION_STATIC );
886 
887     action = rateMenu->addAction( qtr( "N&ormal Speed" ), THEMIM->getIM(),
888                               SLOT( normalRate() ) );
889     action->setData( ACTION_STATIC );
890 
891     action = rateMenu->addAction( QIcon( ":/toolbar/slower2.svg" ), qtr( "Slower (fine)" ), THEMIM->getIM(),
892                               SLOT( littleslower() ) );
893     action->setData( ACTION_STATIC );
894 
895     if( b_normal )
896     {
897         action = rateMenu->addAction( qtr( "Slo&wer" ), THEMIM->getIM(),
898                                   SLOT( slower() ) );
899 #ifndef __APPLE__ /* No icons in menus in Mac */
900         action->setIcon( QIcon( ":/toolbar/slower2.svg") );
901 #endif
902         action->setData( ACTION_STATIC );
903     }
904 
905     action = menu->addMenu( rateMenu );
906     action->setData( ACTION_STATIC );
907 
908     menu->addSeparator();
909 
910     if( !b_normal ) return;
911 
912     action = menu->addAction( qtr( "&Jump Forward" ), THEMIM->getIM(),
913              SLOT( jumpFwd() ) );
914 #ifndef __APPLE__ /* No icons in menus in Mac */
915     action->setIcon( QIcon( ":/toolbar/skip_fw.svg") );
916 #endif
917     action->setData( ACTION_STATIC );
918 
919     action = menu->addAction( qtr( "Jump Bac&kward" ), THEMIM->getIM(),
920              SLOT( jumpBwd() ) );
921 #ifndef __APPLE__ /* No icons in menus in Mac */
922     action->setIcon( QIcon( ":/toolbar/skip_back.svg") );
923 #endif
924     action->setData( ACTION_STATIC );
925 
926     action = menu->addAction( qtr( I_MENU_GOTOTIME ), THEDP, SLOT( gotoTimeDialog() ), qtr( "Ctrl+T" ) );
927     action->setData( ACTION_ALWAYS_ENABLED );
928 
929     menu->addSeparator();
930 }
931 
PopupMenuStaticEntries(QMenu * menu)932 void VLCMenuBar::PopupMenuStaticEntries( QMenu *menu )
933 {
934     QMenu *openmenu = new QMenu( qtr( "Open Media" ), menu );
935     addDPStaticEntry( openmenu, qtr( I_OP_OPF ),
936         ":/type/file-asym.svg", SLOT( openFileDialog() ) );
937     addDPStaticEntry( openmenu, qtr( I_OP_OPDIR ),
938         ":/type/folder-grey.svg", SLOT( PLOpenDir() ) );
939     addDPStaticEntry( openmenu, qtr( "Open &Disc..." ),
940         ":/type/disc.svg", SLOT( openDiscDialog() ) );
941     addDPStaticEntry( openmenu, qtr( "Open &Network..." ),
942         ":/type/network.svg", SLOT( openNetDialog() ) );
943     addDPStaticEntry( openmenu, qtr( "Open &Capture Device..." ),
944         ":/type/capture-card.svg", SLOT( openCaptureDialog() ) );
945     menu->addMenu( openmenu );
946 
947     menu->addSeparator();
948 #if 0
949     QMenu *helpmenu = HelpMenu( menu );
950     helpmenu->setTitle( qtr( "Help" ) );
951     menu->addMenu( helpmenu );
952 #endif
953 
954     addDPStaticEntry( menu, qtr( "Quit" ), ":/menu/exit.svg",
955                       SLOT( quit() ), "Ctrl+Q", QAction::QuitRole );
956 }
957 
958 /* Video Tracks and Subtitles tracks */
VideoPopupMenu(intf_thread_t * p_intf,bool show)959 QMenu* VLCMenuBar::VideoPopupMenu( intf_thread_t *p_intf, bool show )
960 {
961     POPUP_BOILERPLATE
962     if( p_input )
963         VideoAutoMenuBuilder( THEPL, p_input, objects, varnames );
964     CREATE_POPUP
965     return menu;
966 }
967 
968 /* Audio Tracks */
AudioPopupMenu(intf_thread_t * p_intf,bool show)969 QMenu* VLCMenuBar::AudioPopupMenu( intf_thread_t *p_intf, bool show )
970 {
971     POPUP_BOILERPLATE
972     if( p_input )
973         AudioAutoMenuBuilder( p_input, objects, varnames );
974     CREATE_POPUP
975     return menu;
976 }
977 
978 /* Navigation stuff, and general menus ( open ), used only for skins */
MiscPopupMenu(intf_thread_t * p_intf,bool show)979 QMenu* VLCMenuBar::MiscPopupMenu( intf_thread_t *p_intf, bool show )
980 {
981     POPUP_BOILERPLATE
982 
983     menu = new QMenu();
984     if( p_input )
985     {
986         InputAutoMenuBuilder( p_input, objects, varnames );
987         menu->addSeparator();
988     }
989 
990     Populate( p_intf, menu, varnames, objects );
991 
992     menu->addSeparator();
993     PopupMenuPlaylistEntries( menu, p_intf, p_input );
994 
995     menu->addSeparator();
996     PopupMenuControlEntries( menu, p_intf );
997 
998     menu->addSeparator();
999     PopupMenuStaticEntries( menu );
1000 
1001     if( show )
1002         menu->popup( QCursor::pos() );
1003     return menu;
1004 }
1005 
1006 /* Main Menu that sticks everything together  */
PopupMenu(intf_thread_t * p_intf,bool show)1007 QMenu* VLCMenuBar::PopupMenu( intf_thread_t *p_intf, bool show )
1008 {
1009     POPUP_BOILERPLATE
1010 
1011     /* */
1012     menu = new QMenu();
1013     QAction *action;
1014     bool b_isFullscreen = false;
1015     MainInterface *mi = p_intf->p_sys->p_mi;
1016 
1017     PopupMenuPlaylistEntries( menu, p_intf, p_input );
1018     menu->addSeparator();
1019 
1020     if( p_input )
1021     {
1022         QMenu *submenu;
1023         vout_thread_t *p_vout = THEMIM->getVout();
1024 
1025         /* Add a fullscreen switch button, since it is the most used function */
1026         if( p_vout )
1027         {
1028             vlc_value_t val; var_Get( p_vout, "fullscreen", &val );
1029 
1030             b_isFullscreen = !( !val.b_bool );
1031             if( b_isFullscreen )
1032             {
1033                 val.b_bool = false;
1034                 CreateAndConnect( menu, "fullscreen",
1035                         qtr( "Leave Fullscreen" ),"" , ITEM_NORMAL,
1036                         VLC_OBJECT(THEPL), val, VLC_VAR_BOOL, b_isFullscreen );
1037             }
1038             vlc_object_release( p_vout );
1039 
1040             menu->addSeparator();
1041         }
1042 
1043         /* Input menu */
1044         InputAutoMenuBuilder( p_input, objects, varnames );
1045 
1046         /* Audio menu */
1047         submenu = new QMenu( menu );
1048         action = menu->addMenu( AudioMenu( p_intf, submenu ) );
1049         action->setText( qtr( "&Audio" ) );
1050         if( action->menu()->isEmpty() )
1051             action->setEnabled( false );
1052 
1053         /* Video menu */
1054         submenu = new QMenu( menu );
1055         action = menu->addMenu( VideoMenu( p_intf, submenu ) );
1056         action->setText( qtr( "&Video" ) );
1057         if( action->menu()->isEmpty() )
1058             action->setEnabled( false );
1059 
1060         /* Subtitles menu */
1061         submenu = new QMenu( menu );
1062         action = menu->addMenu( SubtitleMenu( p_intf, submenu, true ) );
1063         action->setText( qtr( "Subti&tle") );
1064         UpdateItem( p_intf, submenu, "spu-es", VLC_OBJECT(p_input), true );
1065 
1066         /* Playback menu for chapters */
1067         submenu = new QMenu( menu );
1068         action = menu->addMenu( NavigMenu( p_intf, submenu ) );
1069         action->setText( qtr( "&Playback" ) );
1070         if( action->menu()->isEmpty() )
1071             action->setEnabled( false );
1072     }
1073 
1074     menu->addSeparator();
1075 
1076     /* Add some special entries for windowed mode: Interface Menu */
1077     if( !b_isFullscreen )
1078     {
1079         QMenu *submenu = new QMenu( qtr( "Tool&s" ), menu );
1080         /*QMenu *tools =*/ ToolsMenu( p_intf, submenu );
1081         submenu->addSeparator();
1082 
1083         if( mi )
1084         {
1085             QMenu *bar = menu; // Needed for next macro
1086             BAR_DADD( ViewMenu( p_intf, NULL, mi ), qtr( "V&iew" ), 4 );
1087         }
1088 
1089         /* In skins interface, append some items */
1090         if( p_intf->p_sys->b_isDialogProvider )
1091         {
1092             vlc_object_t* p_object = p_intf->obj.parent;
1093             submenu->setTitle( qtr( "Interface" ) );
1094 
1095             /* Open skin dialog box */
1096             objects.clear(); varnames.clear();
1097             objects.append( p_object );
1098             varnames.append( "intf-skins-interactive" );
1099             Populate( p_intf, submenu, varnames, objects );
1100             QAction* action = submenu->actions().back();
1101             action->setShortcut( QKeySequence( "Ctrl+Shift+S" ));
1102 
1103             /* list of skins available */
1104             objects.clear(); varnames.clear();
1105             objects.append( p_object );
1106             varnames.append( "intf-skins" );
1107             Populate( p_intf, submenu, varnames, objects );
1108 
1109             submenu->addSeparator();
1110 
1111             /* list of extensions */
1112             ExtensionsMenu( p_intf, submenu );
1113         }
1114 
1115         menu->addMenu( submenu );
1116     }
1117 
1118     /* */
1119     QMenuView *plMenu = new QMenuView( menu, 25 );
1120     plMenu->setTitle( qtr("Playlist") );
1121     PLModel *model = PLModel::getPLModel( p_intf );
1122     plMenu->setModel( model );
1123     CONNECT( plMenu, activated(const QModelIndex&),
1124              model, activateItem(const QModelIndex&));
1125     menu->addMenu( plMenu );
1126 
1127     /* Static entries for ending, like open */
1128     if( p_intf->p_sys->b_isDialogProvider )
1129     {
1130         QMenu *openmenu = FileMenu( p_intf, menu );
1131         openmenu->setTitle( qtr( "Open Media" ) );
1132         menu->addMenu( openmenu );
1133 
1134         menu->addSeparator();
1135 
1136         QMenu *helpmenu = HelpMenu( menu );
1137         helpmenu->setTitle( qtr( "Help" ) );
1138         menu->addMenu( helpmenu );
1139 
1140         addDPStaticEntry( menu, qtr( "Quit" ), ":/menu/exit.svg",
1141                           SLOT( quit() ), "Ctrl+Q", QAction::QuitRole );
1142     }
1143     else
1144         PopupMenuStaticEntries( menu );
1145 
1146     if( show )
1147         menu->popup( QCursor::pos() );
1148     return menu;
1149 }
1150 
1151 #undef CREATE_POPUP
1152 #undef POPUP_BOILERPLATE
1153 #undef BAR_DADD
1154 
1155 /************************************************************************
1156  * Systray Menu                                                         *
1157  ************************************************************************/
1158 
updateSystrayMenu(MainInterface * mi,intf_thread_t * p_intf,bool b_force_visible)1159 void VLCMenuBar::updateSystrayMenu( MainInterface *mi,
1160                                   intf_thread_t *p_intf,
1161                                   bool b_force_visible )
1162 {
1163     input_thread_t *p_input = THEMIM->getInput();
1164 
1165     /* Get the systray menu and clean it */
1166     QMenu *sysMenu = mi->getSysTrayMenu();
1167     sysMenu->clear();
1168 
1169 #ifndef Q_OS_MAC
1170     /* Hide / Show VLC and cone */
1171     if( mi->isVisible() || b_force_visible )
1172     {
1173         sysMenu->addAction( QIcon( ":/logo/vlc16.png" ),
1174                             qtr( "&Hide VLC media player in taskbar" ), mi,
1175                             SLOT( hideUpdateSystrayMenu() ) );
1176     }
1177     else
1178     {
1179         sysMenu->addAction( QIcon( ":/logo/vlc16.png" ),
1180                             qtr( "Sho&w VLC media player" ), mi,
1181                             SLOT( showUpdateSystrayMenu() ) );
1182     }
1183     sysMenu->addSeparator();
1184 #endif
1185 
1186     PopupMenuPlaylistEntries( sysMenu, p_intf, p_input );
1187     PopupMenuControlEntries( sysMenu, p_intf, false );
1188 
1189     VolumeEntries( p_intf, sysMenu );
1190     sysMenu->addSeparator();
1191     addDPStaticEntry( sysMenu, qtr( "&Open Media" ),
1192             ":/type/file-wide.svg", SLOT( openFileDialog() ) );
1193     addDPStaticEntry( sysMenu, qtr( "&Quit" ) ,
1194             ":/menu/exit.svg", SLOT( quit() ) );
1195 
1196     /* Set the menu */
1197     mi->getSysTray()->setContextMenu( sysMenu );
1198 }
1199 
1200 
1201 #undef PUSH_VAR
1202 
1203 /*************************************************************************
1204  * Builders for automenus
1205  *************************************************************************/
Populate(intf_thread_t * p_intf,QMenu * current,QVector<const char * > & varnames,QVector<vlc_object_t * > & objects)1206 QMenu * VLCMenuBar::Populate( intf_thread_t *p_intf,
1207                             QMenu *current,
1208                             QVector< const char *> & varnames,
1209                             QVector<vlc_object_t *> & objects )
1210 {
1211     QMenu *menu = current;
1212     assert( menu );
1213 
1214     currentGroup = NULL;
1215 
1216     for( int i = 0; i < (int)objects.count() ; i++ )
1217     {
1218         if( !varnames[i] || !*varnames[i] )
1219         {
1220             menu->addSeparator();
1221             continue;
1222         }
1223 
1224         UpdateItem( p_intf, menu, varnames[i], objects[i], true );
1225     }
1226     return menu;
1227 }
1228 
1229 /*****************************************************************************
1230  * Private methods.
1231  *****************************************************************************/
1232 
IsMenuEmpty(const char * psz_var,vlc_object_t * p_object)1233 static bool IsMenuEmpty( const char *psz_var, vlc_object_t *p_object )
1234 {
1235     /* Check if we want to display the variable */
1236     if( !(var_Type( p_object, psz_var) & VLC_VAR_HASCHOICE) )
1237         return false;
1238 
1239     vlc_value_t val;
1240     var_Change( p_object, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
1241     return val.i_int == 0 || val.i_int == 1;
1242 }
1243 
1244 #define TEXT_OR_VAR qfue ( text.psz_string ? text.psz_string : psz_var )
1245 
UpdateItem(intf_thread_t * p_intf,QMenu * menu,const char * psz_var,vlc_object_t * p_object,bool b_submenu)1246 void VLCMenuBar::UpdateItem( intf_thread_t *p_intf, QMenu *menu,
1247         const char *psz_var, vlc_object_t *p_object, bool b_submenu )
1248 {
1249     vlc_value_t val, text;
1250     int i_type;
1251 
1252     QAction *action = FindActionWithVar( menu, psz_var );
1253     if( action )
1254         DeleteNonStaticEntries( action->menu() );
1255 
1256     if( !p_object )
1257     {
1258         if( action )
1259             action->setEnabled( false );
1260         return;
1261     }
1262 
1263     /* Check the type of the object variable */
1264     /* This HACK is needed so that we have:
1265      *  - a radio button for audio/video tracks instread of a checkbox, and;
1266      *  - an always enabled bookmark menu (even if there are no bookmarks)
1267      **/
1268     if( !strcmp( psz_var, "audio-es" )
1269      || !strcmp( psz_var, "video-es" )
1270      || !strcmp( psz_var, "bookmark" ) )
1271         i_type = VLC_VAR_INTEGER | VLC_VAR_HASCHOICE;
1272     else
1273         i_type = var_Type( p_object, psz_var );
1274 
1275     switch( i_type & VLC_VAR_TYPE )
1276     {
1277         case VLC_VAR_VOID:
1278         case VLC_VAR_BOOL:
1279         case VLC_VAR_STRING:
1280         case VLC_VAR_INTEGER:
1281         case VLC_VAR_FLOAT:
1282             break;
1283         default:
1284             /* Variable doesn't exist or isn't handled */
1285             if( action )
1286                 action->setEnabled( false );
1287             return;
1288     }
1289 
1290     /* Make sure we want to display the variable */
1291     if( menu->isEmpty() && IsMenuEmpty( psz_var, p_object ) )
1292     {
1293         if( action )
1294             action->setEnabled( false );
1295         return;
1296     }
1297 
1298     /* Get the descriptive name of the variable */
1299     int i_ret = var_Change( p_object, psz_var, VLC_VAR_GETTEXT, &text, NULL );
1300     if( i_ret != VLC_SUCCESS )
1301     {
1302         text.psz_string = NULL;
1303     }
1304 
1305     if( !action )
1306     {
1307         action = new QAction( TEXT_OR_VAR, menu );
1308         menu->addAction( action );
1309         action->setData( psz_var );
1310     }
1311 
1312     if( i_type & VLC_VAR_HASCHOICE )
1313     {
1314         /* Append choices menu */
1315         if( b_submenu )
1316         {
1317             QMenu *submenu;
1318             submenu = action->menu();
1319             if( !submenu )
1320             {
1321                 submenu = new QMenu( menu );
1322                 action->setMenu( submenu );
1323             }
1324 
1325             action->setEnabled(
1326                 CreateChoicesMenu( submenu, psz_var, p_object ) == 0 );
1327         }
1328         else
1329         {
1330             action->setEnabled(
1331                 CreateChoicesMenu( menu, psz_var, p_object ) == 0 );
1332         }
1333         FREENULL( text.psz_string );
1334         return;
1335     }
1336     else
1337         action->setEnabled( false );
1338 
1339     switch( i_type & VLC_VAR_TYPE )
1340     {
1341         case VLC_VAR_VOID:
1342             val.i_int = 0;  // Prevent the copy of an uninitialized value
1343             CreateAndConnect( menu, psz_var, TEXT_OR_VAR, "", ITEM_NORMAL,
1344                     p_object, val, i_type );
1345             break;
1346 
1347         case VLC_VAR_BOOL:
1348             var_Get( p_object, psz_var, &val );
1349             val.b_bool = !val.b_bool;
1350             CreateAndConnect( menu, psz_var, TEXT_OR_VAR, "", ITEM_CHECK,
1351                     p_object, val, i_type, !val.b_bool );
1352             break;
1353     }
1354     FREENULL( text.psz_string );
1355 }
1356 
1357 #undef TEXT_OR_VAR
1358 
1359 /** HACK for the navigation submenu:
1360  * "title %2u" variables take the value 0 if not set
1361  */
CheckTitle(vlc_object_t * p_object,const char * psz_var)1362 static bool CheckTitle( vlc_object_t *p_object, const char *psz_var )
1363 {
1364     unsigned i_title = 0;
1365     if( sscanf( psz_var, "title %2u", &i_title ) <= 0 )
1366         return true;
1367 
1368     unsigned i_current_title = var_GetInteger( p_object, "title" );
1369     return ( i_title == i_current_title );
1370 }
1371 
1372 
CreateChoicesMenu(QMenu * submenu,const char * psz_var,vlc_object_t * p_object)1373 int VLCMenuBar::CreateChoicesMenu( QMenu *submenu, const char *psz_var,
1374                                    vlc_object_t *p_object )
1375 {
1376     vlc_value_t val, val_list, text_list;
1377     int i_type, i;
1378 
1379     /* Check the type of the object variable */
1380     i_type = var_Type( p_object, psz_var );
1381 
1382     /* Make sure we want to display the variable */
1383     if( submenu->isEmpty() && IsMenuEmpty( psz_var, p_object ) )
1384         return VLC_EGENERIC;
1385 
1386     switch( i_type & VLC_VAR_TYPE )
1387     {
1388         case VLC_VAR_VOID:
1389         case VLC_VAR_BOOL:
1390         case VLC_VAR_STRING:
1391         case VLC_VAR_INTEGER:
1392         case VLC_VAR_FLOAT:
1393             break;
1394         default:
1395             /* Variable doesn't exist or isn't handled */
1396             return VLC_EGENERIC;
1397     }
1398 
1399     if( var_Change( p_object, psz_var, VLC_VAR_GETCHOICES,
1400                     &val_list, &text_list ) < 0 )
1401     {
1402         return VLC_EGENERIC;
1403     }
1404 
1405 #define CURVAL val_list.p_list->p_values[i]
1406 #define CURTEXT text_list.p_list->p_values[i].psz_string
1407 #define RADIO_OR_COMMAND  ( i_type & ( VLC_VAR_ISCOMMAND | VLC_VAR_HASCHOICE ) ) ? ITEM_RADIO : ITEM_NORMAL
1408 
1409     for( i = 0; i < val_list.p_list->i_count; i++ )
1410     {
1411         vlc_value_t another_val;
1412         QString menutext;
1413 
1414         switch( i_type & VLC_VAR_TYPE )
1415         {
1416             case VLC_VAR_STRING:
1417                 var_Get( p_object, psz_var, &val );
1418                 another_val.psz_string = strdup( CURVAL.psz_string );
1419                 menutext = qfue( CURTEXT ? CURTEXT : another_val.psz_string );
1420                 CreateAndConnect( submenu, psz_var, menutext, "", RADIO_OR_COMMAND,
1421                         p_object, another_val, i_type,
1422                         val.psz_string && !strcmp( val.psz_string, CURVAL.psz_string ) );
1423 
1424                 free( val.psz_string );
1425                 break;
1426 
1427             case VLC_VAR_INTEGER:
1428                 var_Get( p_object, psz_var, &val );
1429                 if( CURTEXT ) menutext = qfue( CURTEXT );
1430                 else menutext = QString::number( CURVAL.i_int );
1431                 CreateAndConnect( submenu, psz_var, menutext, "", RADIO_OR_COMMAND,
1432                         p_object, CURVAL, i_type,
1433                         ( CURVAL.i_int == val.i_int )
1434                         && CheckTitle( p_object, psz_var ) );
1435                 break;
1436 
1437             case VLC_VAR_FLOAT:
1438                 var_Get( p_object, psz_var, &val );
1439                 if( CURTEXT ) menutext = qfue( CURTEXT );
1440                 else menutext.sprintf( "%.2f", CURVAL.f_float );
1441                 CreateAndConnect( submenu, psz_var, menutext, "", RADIO_OR_COMMAND,
1442                         p_object, CURVAL, i_type,
1443                         CURVAL.f_float == val.f_float );
1444                 break;
1445 
1446             default:
1447                 break;
1448         }
1449     }
1450     currentGroup = NULL;
1451 
1452     /* clean up everything */
1453     var_FreeList( &val_list, &text_list );
1454 
1455 #undef RADIO_OR_COMMAND
1456 #undef CURVAL
1457 #undef CURTEXT
1458 
1459     return submenu->isEmpty() ? VLC_EGENERIC : VLC_SUCCESS;
1460 }
1461 
CreateAndConnect(QMenu * menu,const char * psz_var,const QString & text,const QString & help,int i_item_type,vlc_object_t * p_obj,vlc_value_t val,int i_val_type,bool checked)1462 void VLCMenuBar::CreateAndConnect( QMenu *menu, const char *psz_var,
1463         const QString& text, const QString& help,
1464         int i_item_type, vlc_object_t *p_obj,
1465         vlc_value_t val, int i_val_type,
1466         bool checked )
1467 {
1468     QAction *action = FindActionWithVar( menu, psz_var );
1469 
1470     bool b_new = false;
1471     if( !action )
1472     {
1473         action = new QAction( text, menu );
1474         menu->addAction( action );
1475         b_new = true;
1476     }
1477 
1478     action->setToolTip( help );
1479     action->setEnabled( p_obj != NULL );
1480 
1481     if( i_item_type == ITEM_CHECK )
1482     {
1483         action->setCheckable( true );
1484     }
1485     else if( i_item_type == ITEM_RADIO )
1486     {
1487         action->setCheckable( true );
1488         if( !currentGroup )
1489             currentGroup = new QActionGroup( menu );
1490         currentGroup->addAction( action );
1491     }
1492 
1493     action->setChecked( checked );
1494 
1495     MenuItemData *itemData = action->findChild<MenuItemData*>( QString() );
1496     delete itemData;
1497     itemData = new MenuItemData( action, p_obj, i_val_type, val, psz_var );
1498 
1499     /* remove previous signal-slot connection(s) if any */
1500     action->disconnect( );
1501 
1502     CONNECT( action, triggered(), THEDP->menusMapper, map() );
1503     THEDP->menusMapper->setMapping( action, itemData );
1504 
1505     if( b_new )
1506         menu->addAction( action );
1507 }
1508 
DoAction(QObject * data)1509 void VLCMenuBar::DoAction( QObject *data )
1510 {
1511     MenuItemData *itemData = qobject_cast<MenuItemData *>( data );
1512     vlc_object_t *p_object = itemData->p_obj;
1513     if( p_object == NULL ) return;
1514     const char *var = itemData->psz_var;
1515     vlc_value_t val = itemData->val;
1516 
1517     if ((var_Type( p_object, var) & VLC_VAR_CLASS) == VLC_VAR_VOID)
1518         var_TriggerCallback( p_object, var );
1519     else
1520         var_Set( p_object, var, val );
1521 
1522     if( !strcmp( var, "fullscreen" )
1523      || !strcmp( var, "video-on-top" )
1524      || !strcmp( var, "video-wallpaper" ) ) /* FIXME: reverse abstraction */
1525     {   /* Apply playlist variables to current existing vout too */
1526         input_thread_t *input = playlist_CurrentInput((playlist_t *)p_object);
1527         if( input != NULL )
1528         {
1529             vout_thread_t *vout = input_GetVout( input );
1530             vlc_object_release( input );
1531             if( vout != NULL )
1532             {
1533                 var_Set( vout, var, val ); /* never void class */
1534                 vlc_object_release( vout );
1535             }
1536         }
1537     }
1538 }
1539 
updateAudioDevice(intf_thread_t * p_intf,audio_output_t * p_aout,QMenu * current)1540 void VLCMenuBar::updateAudioDevice( intf_thread_t * p_intf, audio_output_t *p_aout, QMenu *current )
1541 {
1542     char **ids, **names;
1543     char *selected;
1544 
1545     if( !p_aout || !current )
1546         return;
1547 
1548     current->clear();
1549     int i_result = aout_DevicesList( p_aout, &ids, &names);
1550     if( i_result < 0 )
1551         return;
1552 
1553     selected = aout_DeviceGet( p_aout );
1554 
1555     QActionGroup *actionGroup = new QActionGroup(current);
1556     QAction *action;
1557 
1558     for( int i = 0; i < i_result; i++ )
1559     {
1560         action = new QAction( qfue( names[i] ), actionGroup );
1561         action->setData( ids[i] );
1562         action->setCheckable( true );
1563         if( (selected && !strcmp( ids[i], selected ) ) ||
1564             (selected == NULL && ids[i] && ids[i][0] == '\0' ) )
1565             action->setChecked( true );
1566         actionGroup->addAction( action );
1567         current->addAction( action );
1568         CONNECT(action, triggered(), THEMIM->menusAudioMapper, map());
1569         THEMIM->menusAudioMapper->setMapping(action, ids[i]);
1570         free( ids[i] );
1571         free( names[i] );
1572     }
1573     free( ids );
1574     free( names );
1575     free( selected );
1576 }
1577 
updateRecents(intf_thread_t * p_intf)1578 void VLCMenuBar::updateRecents( intf_thread_t *p_intf )
1579 {
1580     if( recentsMenu )
1581     {
1582         QAction* action;
1583         RecentsMRL* rmrl = RecentsMRL::getInstance( p_intf );
1584         QStringList l = rmrl->recentList();
1585 
1586         recentsMenu->clear();
1587 
1588         if( !l.count() )
1589         {
1590             recentsMenu->setEnabled( false );
1591         }
1592         else
1593         {
1594             for( int i = 0; i < __MIN( l.count(), 10) ; ++i )
1595             {
1596                 QString mrl = l.at( i );
1597                 char *psz = vlc_uri_decode_duplicate( qtu( mrl ) );
1598                 QString text = qfu( psz );
1599 
1600                 text.replace("&", "&&");
1601 #ifdef _WIN32
1602 # define FILE_SCHEME "file:///"
1603 #else
1604 # define FILE_SCHEME "file://"
1605 #endif
1606                 if ( text.startsWith( FILE_SCHEME ) )
1607                     text.remove( 0, strlen( FILE_SCHEME ) );
1608 #undef FILE_SCHEME
1609 
1610                 free( psz );
1611                 action = recentsMenu->addAction(
1612                         QString( i < 9 ? "&%1: ": "%1: " ).arg( i + 1 ) +
1613                             QApplication::fontMetrics().elidedText( text,
1614                                                           Qt::ElideLeft, 400 ),
1615                         rmrl->signalMapper, SLOT( map() ),
1616                         i < 9 ? QString( "Ctrl+%1" ).arg( i + 1 ) : "" );
1617                 rmrl->signalMapper->setMapping( action, l.at( i ) );
1618             }
1619 
1620             recentsMenu->addSeparator();
1621             recentsMenu->addAction( qtr("&Clear"), rmrl, SLOT( clear() ) );
1622             recentsMenu->setEnabled( true );
1623         }
1624     }
1625 }
1626 
RendererMenu(intf_thread_t * p_intf,QMenu * menu)1627 QMenu *VLCMenuBar::RendererMenu(intf_thread_t *p_intf, QMenu *menu )
1628 {
1629     QMenu *submenu = new QMenu( qtr("&Renderer"), menu );
1630 
1631     rendererGroup = new QActionGroup(submenu);
1632 
1633     QAction *action = new QAction( qtr("<Local>"), submenu );
1634     action->setCheckable(true);
1635     submenu->addAction( action );
1636     rendererGroup->addAction(action);
1637 
1638     char *psz_renderer = var_InheritString( THEPL, "sout" );
1639     if ( psz_renderer == NULL )
1640         action->setChecked( true );
1641     else
1642         free( psz_renderer );
1643 
1644     submenu->addSeparator();
1645 
1646     action = new QAction( qtr("Scanning..."), submenu );
1647     action->setEnabled( false );
1648     submenu->addAction( action );
1649 
1650     CONNECT( submenu, aboutToShow(), ActionsManager::getInstance( p_intf ), StartRendererScan() );
1651     CONNECT( submenu, aboutToHide(), ActionsManager::getInstance( p_intf ), RendererMenuCountdown() );
1652     CONNECT( rendererGroup, triggered(QAction*), ActionsManager::getInstance( p_intf ), RendererSelected( QAction* ) );
1653 
1654     return submenu;
1655 }
1656