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