menus.cpp 32 KB
Newer Older
zorglub's avatar
zorglub committed
1 2 3
/*****************************************************************************
 * menus.cpp : Qt menus
 *****************************************************************************
4
 * Copyright (C) 2006-2007 the VideoLAN team
5
 * $Id$
zorglub's avatar
zorglub committed
6
 *
7
 * Authors: Clment Stenac <zorglub@videolan.org>
8
 *          Jean-Baptiste Kempf <jb@videolan.org>
zorglub's avatar
zorglub committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

25 26 27 28
#ifndef WIN32
#   include <signal.h>
#endif

zorglub's avatar
zorglub committed
29
#include <vlc_intf_strings.h>
zorglub's avatar
zorglub committed
30

zorglub's avatar
zorglub committed
31
#include "main_interface.hpp"
zorglub's avatar
zorglub committed
32 33 34 35
#include "menus.hpp"
#include "dialogs_provider.hpp"
#include "input_manager.hpp"

36 37 38 39 40 41 42
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QActionGroup>
#include <QSignalMapper>
#include <QSystemTrayIcon>

zorglub's avatar
zorglub committed
43 44 45 46 47 48 49 50 51
enum
{
    ITEM_NORMAL,
    ITEM_CHECK,
    ITEM_RADIO
};

static QActionGroup *currentGroup;

52
// Add static entries to menus
53
#define DP_SADD( menu, text, help, icon, slot, shortcut ) \
54
{ \
55
    if( strlen( icon ) > 0 ) \
56
    { \
57
        if( strlen( shortcut ) > 0 ) \
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
58
        { \
59 60
            menu->addAction( QIcon( icon ), text, THEDP, SLOT( slot ), \
                    qtr( shortcut ) );\
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
61 62 63
        } \
        else \
        { \
64
            menu->addAction( QIcon( icon ), text, THEDP, SLOT( slot ) );\
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
65
        } \
66 67 68
    } \
    else \
    { \
69
        if( strlen( shortcut ) > 0 ) \
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
70 71
        { \
            menu->addAction( text, THEDP, SLOT( slot ), \
72
                    qtr( shortcut ) ); \
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
73 74 75 76 77
        } \
        else \
        { \
            menu->addAction( text, THEDP, SLOT( slot ) ); \
        } \
78
    } \
79
}
80
#define MIM_SADD( menu, text, help, icon, slot ) \
81
{ \
82
    if( strlen( icon ) > 0 ) \
83 84
    { \
        QAction *action = menu->addAction( text, THEMIM, SLOT( slot ) ); \
85
        action->setIcon( QIcon( icon ) ); \
86 87 88 89 90
    } \
    else \
    { \
        menu->addAction( text, THEMIM, SLOT( slot ) ); \
    } \
91
}
zorglub's avatar
Qt4:  
zorglub committed
92
#define PL_SADD
zorglub's avatar
zorglub committed
93 94

/*****************************************************************************
95
 * Definitions of variables for the dynamic menus
zorglub's avatar
zorglub committed
96
 *****************************************************************************/
97
#define PUSH_VAR( var ) varnames.push_back( var ); \
98
    objects.push_back( p_object->i_object_id )
99 100

#define PUSH_SEPARATOR if( objects.size() != i_last_separator ) { \
101 102
    objects.push_back( 0 ); varnames.push_back( "" ); \
    i_last_separator = objects.size(); }
zorglub's avatar
zorglub committed
103 104

static int InputAutoMenuBuilder( vlc_object_t *p_object,
105 106
        vector<int> &objects,
        vector<const char *> &varnames )
zorglub's avatar
zorglub committed
107 108 109 110 111 112 113 114 115 116
{
    PUSH_VAR( "bookmark");
    PUSH_VAR( "title" );
    PUSH_VAR ("chapter" );
    PUSH_VAR( "program" );
    PUSH_VAR( "navigation" );
    PUSH_VAR( "dvd_menus" );
    return VLC_SUCCESS;
}

zorglub's avatar
Qt4:  
zorglub committed
117
static int VideoAutoMenuBuilder( vlc_object_t *p_object,
118 119
        vector<int> &objects,
        vector<const char *> &varnames )
zorglub's avatar
zorglub committed
120 121 122 123 124 125 126 127 128 129 130
{
    PUSH_VAR( "fullscreen" );
    PUSH_VAR( "zoom" );
    PUSH_VAR( "deinterlace" );
    PUSH_VAR( "aspect-ratio" );
    PUSH_VAR( "crop" );
    PUSH_VAR( "video-on-top" );
    PUSH_VAR( "directx-wallpaper" );
    PUSH_VAR( "video-snapshot" );

    vlc_object_t *p_dec_obj = (vlc_object_t *)vlc_object_find( p_object,
131 132
            VLC_OBJECT_DECODER,
            FIND_PARENT );
zorglub's avatar
zorglub committed
133 134
    if( p_dec_obj != NULL )
    {
135
        vlc_object_t *p_object = p_dec_obj;
zorglub's avatar
zorglub committed
136 137 138 139 140 141 142
        PUSH_VAR( "ffmpeg-pp-q" );
        vlc_object_release( p_dec_obj );
    }
    return VLC_SUCCESS;
}

static int AudioAutoMenuBuilder( vlc_object_t *p_object,
143 144
        vector<int> &objects,
        vector<const char *> &varnames )
zorglub's avatar
zorglub committed
145 146 147 148 149 150 151 152
{
    PUSH_VAR( "audio-device" );
    PUSH_VAR( "audio-channels" );
    PUSH_VAR( "visual" );
    PUSH_VAR( "equalizer" );
    return VLC_SUCCESS;
}

153 154
/*****************************************************************************
 * All normal menus
155
 * Simple Code
156 157 158 159 160 161 162 163
 *****************************************************************************/

#define BAR_ADD( func, title ) { \
    QMenu *menu = func; menu->setTitle( title  ); bar->addMenu( menu ); }

#define BAR_DADD( func, title, id ) { \
    QMenu *menu = func; menu->setTitle( title  ); bar->addMenu( menu ); \
    MenuFunc *f = new MenuFunc( menu, id ); \
zorglub's avatar
zorglub committed
164
    CONNECT( menu, aboutToShow(), THEDP->menusUpdateMapper, map() ); \
165 166
    THEDP->menusUpdateMapper->setMapping( menu, f ); }

167 168 169
/**
 * Main Menu Bar Creation
 **/
zorglub's avatar
zorglub committed
170
void QVLCMenu::createMenuBar( MainInterface *mi, intf_thread_t *p_intf,
171 172
        bool playlist, bool adv_controls_enabled,
        bool visual_selector_enabled )
zorglub's avatar
Qt4:  
zorglub committed
173
{
174
#ifndef WIN32
175
    /* Ugly klugde
176 177 178 179 180 181
     * Remove SIGCHLD from the ignored signal the time to initialise
     * Qt because it call gconf to get the icon theme */
    sigset_t set;

    sigemptyset( &set );
    sigaddset( &set, SIGCHLD );
182
    pthread_sigmask( SIG_UNBLOCK, &set, NULL );
183
#endif /* WIN32 */
zorglub's avatar
zorglub committed
184
    QMenuBar *bar = mi->menuBar();
185
#ifndef WIN32
186
    pthread_sigmask( SIG_BLOCK, &set, NULL );
187
#endif /* WIN32 */
188
    BAR_ADD( FileMenu(), qtr("&Media") );
zorglub's avatar
zorglub committed
189 190
    if( playlist )
    {
191
        BAR_ADD( PlaylistMenu( mi,p_intf ), qtr("&Playlist" ) );
zorglub's avatar
zorglub committed
192
    }
193
    BAR_ADD( ToolsMenu( p_intf, mi, adv_controls_enabled,
194
                visual_selector_enabled ), qtr("&Tools") );
195 196 197
    BAR_DADD( VideoMenu( p_intf, NULL ), qtr("&Video"), 1 );
    BAR_DADD( AudioMenu( p_intf, NULL ), qtr("&Audio"), 2 );
    BAR_DADD( NavigMenu( p_intf, NULL ), qtr("&Navigation"), 3 );
198

199
    BAR_ADD( HelpMenu(), qtr("&Help" ) );
200
}
201 202 203 204 205

/**
 * Media (File) Menu
 * Opening, streaming and quit
 **/
206 207 208
QMenu *QVLCMenu::FileMenu()
{
    QMenu *menu = new QMenu();
209 210
    DP_SADD( menu, qtr("Open &File..." ), "",
            ":/pixmaps/vlc_file-asym_16px.png", openFileDialog(), "Ctrl+O" );
211 212 213 214 215 216 217 218 219 220

    /* Folder vs. Directory */
#ifdef WIN32
    DP_SADD( menu, qtr( "Open Folder..." ), "",
            ":/pixmaps/vlc_folder-grey_16px.png", openDirDialog(), "Ctrl+F" );
#else
    DP_SADD( menu, qtr( "Open Directory..." ), "",
            ":/pixmaps/vlc_folder-grey_16px.png", openDirDialog(), "Ctrl+F" );
#endif /* WIN32 */

221 222
    DP_SADD( menu, qtr("Open &Disc..." ), "", ":/pixmaps/vlc_disc_16px.png",
             openDiscDialog(), "Ctrl+D" );
223 224 225 226
    DP_SADD( menu, qtr("Open &Network..." ), "",
                ":/pixmaps/vlc_network_16px.png", openNetDialog(), "Ctrl+N" );
    DP_SADD( menu, qtr("Open &Capture Device..." ), "",
            ":/pixmaps/vlc_capture-card_16px.png", openCaptureDialog(),
227
            "Ctrl+C" );
228
    menu->addSeparator();
229 230
    DP_SADD( menu, qtr("&Streaming..."), "", ":/pixmaps/vlc_stream_16px.png",
            openThenStreamingDialogs(), "Ctrl+S" );
231 232
    DP_SADD( menu, qtr("Conve&rt / Save..."), "", "",
            openThenTranscodingDialogs(), "Ctrl+R" );
233
    menu->addSeparator();
234
    DP_SADD( menu, qtr("&Quit") , "", ":/pixmaps/vlc_quit_16px.png", quit(),
235
            "Ctrl+Q");
236 237 238
    return menu;
}

239
/* Playlist Menu, undocked when playlist is undocked */
zorglub's avatar
zorglub committed
240
QMenu *QVLCMenu::PlaylistMenu( MainInterface *mi, intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
241 242 243
{
    QMenu *menu = new QMenu();
    menu->addMenu( SDMenu( p_intf ) );
244 245
    menu->addAction ( QIcon(":/pixmaps/vlc_playlist_16px.png"),
                      qtr( "Playlist"), mi, SLOT( playlist() ) );
zorglub's avatar
zorglub committed
246 247
    menu->addSeparator();

248 249
    DP_SADD( menu, qtr( I_PL_LOAD ), "", "", openPlaylist(), "Ctrl+L" );
    DP_SADD( menu, qtr( I_PL_SAVE ), "", "", savePlaylist(), "Ctrl+K" );
zorglub's avatar
zorglub committed
250 251
    menu->addSeparator();
    menu->addAction( qtr("Undock from interface"), mi,
252
            SLOT( undockPlaylist() ), qtr("Ctrl+U") );
zorglub's avatar
zorglub committed
253 254 255
    return menu;
}

256 257 258 259 260
/**
 * Tools/View Menu
 * This is kept in the same menu for now, but could change if it gets much 
 * longer.
 **/
zorglub's avatar
zorglub committed
261
QMenu *QVLCMenu::ToolsMenu( intf_thread_t *p_intf, MainInterface *mi,
262 263
        bool adv_controls_enabled,
        bool visual_selector_enabled, bool with_intf )
264 265 266 267 268
{
    QMenu *menu = new QMenu();
    if( with_intf )
    {
        QMenu *intfmenu = InterfacesMenu( p_intf, NULL );
zorglub's avatar
zorglub committed
269
        intfmenu->setTitle( qtr("Interfaces" ) );
270 271 272
        menu->addMenu( intfmenu );
        menu->addSeparator();
    }
273
    DP_SADD( menu, qtr( I_MENU_MSG ), "", ":/pixmaps/vlc_messages_16px.png",
274
             messagesDialog(), "Ctrl+M" );
275 276
    DP_SADD( menu, qtr( I_MENU_INFO ) , "", "", mediaInfoDialog(), "Ctrl+J" );
    DP_SADD( menu, qtr( I_MENU_CODECINFO ) , "", ":/pixmaps/vlc_info_16px.png",
277
             mediaCodecDialog(), "Ctrl+I" );
278
    DP_SADD( menu, qtr( I_MENU_GOTOTIME ), "","", gotoTimeDialog(), "Ctrl+T" );
279
#if 0 /* Not Implemented yet */
280 281
    DP_SADD( menu, qtr( I_MENU_BOOKMARK ), "","", bookmarksDialog(), "Ctrl+B" );
    DP_SADD( menu, qtr( I_MENU_VLM ), "","", vlmDialog(), "Ctrl+V" );
282
#endif
283

284
    menu->addSeparator();
zorglub's avatar
zorglub committed
285 286 287
    if( mi )
    {
        QAction *adv = menu->addAction( qtr("Advanced controls" ),
288
                mi, SLOT( advanced() ) );
zorglub's avatar
zorglub committed
289 290
        adv->setCheckable( true );
        if( adv_controls_enabled ) adv->setChecked( true );
291

292 293
        menu->addAction( qtr( "Hide Menus..." ), mi, SLOT( toggleMenus() ),
                qtr( "Ctrl+H") );
294
        menu->addSeparator();
295

296
#if 0 /* For Visualisations. Not yet working */
297
        adv = menu->addAction( qtr("Visualizations selector" ),
298
                mi, SLOT( visual() ) );
299 300
        adv->setCheckable( true );
        if( visual_selector_enabled ) adv->setChecked( true );
301
#endif
302 303
        menu->addAction ( QIcon(":/pixmaps/vlc_playlist_16px.png"),
                          qtr( "Playlist"), mi, SLOT( playlist() ) );
zorglub's avatar
zorglub committed
304
    }
305 306
    DP_SADD( menu, qtr( I_MENU_EXT ), "", ":/pixmaps/vlc_settings_16px.png",
                 extendedDialog() ,  "Ctrl+E"  );
307

308
    menu->addSeparator();
309 310
    DP_SADD( menu, qtr("Preferences"), "", ":/pixmaps/vlc_preferences_16px.png",
             prefsDialog(), "Ctrl+P" );
311 312 313
    return menu;
}

314 315 316
/**
 * Interface Sub-Menu, to list extras interface and skins
 **/
317 318 319 320 321 322 323
QMenu *QVLCMenu::InterfacesMenu( intf_thread_t *p_intf, QMenu *current )
{
    vector<int> objects;
    vector<const char *> varnames;
    /** \todo add "switch to XXX" */
    varnames.push_back( "intf-add" );
    objects.push_back( p_intf->i_object_id );
zorglub's avatar
Qt4:  
zorglub committed
324

325
    QMenu *menu = Populate( p_intf, current, varnames, objects );
zorglub's avatar
zorglub committed
326 327 328 329

    if( !p_intf->pf_show_dialog )
    {
        menu->addSeparator();
330
        menu->addAction( qtr("Switch to skins"), THEDP, SLOT( switchToSkins() ),
Christophe Mutricy's avatar
Christophe Mutricy committed
331
                QString("Ctrl+Z") );
zorglub's avatar
zorglub committed
332 333
    }

zorglub's avatar
zorglub committed
334
    CONNECT( menu, aboutToShow(), THEDP->menusUpdateMapper, map() );
335 336 337 338
    THEDP->menusUpdateMapper->setMapping( menu, 4 );
    return menu;
}

339 340 341
/**
 * Main Audio Menu
 */
342 343 344 345 346 347
QMenu *QVLCMenu::AudioMenu( intf_thread_t *p_intf, QMenu * current )
{
    vector<int> objects;
    vector<const char *> varnames;

    vlc_object_t *p_object = (vlc_object_t *)vlc_object_find( p_intf,
348
            VLC_OBJECT_INPUT, FIND_ANYWHERE );
349 350 351 352 353 354 355
    if( p_object != NULL )
    {
        PUSH_VAR( "audio-es" );
        vlc_object_release( p_object );
    }

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_AOUT,
356
            FIND_ANYWHERE );
357 358 359 360 361 362 363 364
    if( p_object )
    {
        AudioAutoMenuBuilder( p_object, objects, varnames );
        vlc_object_release( p_object );
    }
    return Populate( p_intf, current, varnames, objects );
}

365 366 367 368
/**
 * Main Video Menu
 * Subtitles are part of Video.
 **/
369
QMenu *QVLCMenu::VideoMenu( intf_thread_t *p_intf, QMenu *current )
zorglub's avatar
zorglub committed
370 371
{
    vlc_object_t *p_object;
372 373 374 375
    vector<int> objects;
    vector<const char *> varnames;

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
376
            FIND_ANYWHERE );
zorglub's avatar
zorglub committed
377 378
    if( p_object != NULL )
    {
379 380
        PUSH_VAR( "video-es" );
        PUSH_VAR( "spu-es" );
zorglub's avatar
zorglub committed
381 382
        vlc_object_release( p_object );
    }
383 384

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
385
            FIND_ANYWHERE );
386 387 388 389 390 391
    if( p_object != NULL )
    {
        VideoAutoMenuBuilder( p_object, objects, varnames );
        vlc_object_release( p_object );
    }
    return Populate( p_intf, current, varnames, objects );
zorglub's avatar
zorglub committed
392 393
}

394 395 396 397
/**
 * Navigation Menu
 * For DVD, MP4, MOV and other chapter based format
 **/
398 399 400 401 402
QMenu *QVLCMenu::NavigMenu( intf_thread_t *p_intf, QMenu *current )
{
    vlc_object_t *p_object;
    vector<int> objects;
    vector<const char *> varnames;
zorglub's avatar
zorglub committed
403

404 405
    /* FIXME */
    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
406
            FIND_ANYWHERE );
407 408 409 410 411 412 413 414 415
    if( p_object != NULL )
    {
        InputAutoMenuBuilder( p_object, objects, varnames );
        PUSH_VAR( "prev-title"); PUSH_VAR ( "next-title" );
        PUSH_VAR( "prev-chapter"); PUSH_VAR( "next-chapter" );
        vlc_object_release( p_object );
    }
    return Populate( p_intf, current, varnames, objects );
}
zorglub's avatar
zorglub committed
416

417 418 419
/**
 * Service Discovery Menu
 **/
zorglub's avatar
zorglub committed
420 421 422
QMenu *QVLCMenu::SDMenu( intf_thread_t *p_intf )
{
    QMenu *menu = new QMenu();
423
    menu->setTitle( qtr( I_PL_SD ) );
zorglub's avatar
zorglub committed
424
    vlc_list_t *p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE,
425
            FIND_ANYWHERE );
zorglub's avatar
zorglub committed
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
    int i_num = 0;
    for( int i_index = 0 ; i_index < p_list->i_count; i_index++ )
    {
        module_t * p_parser = (module_t *)p_list->p_values[i_index].p_object ;
        if( !strcmp( p_parser->psz_capability, "services_discovery" ) )
            i_num++;
    }
    for( int i_index = 0 ; i_index < p_list->i_count; i_index++ )
    {
        module_t * p_parser = (module_t *)p_list->p_values[i_index].p_object;
        if( !strcmp( p_parser->psz_capability, "services_discovery" ) )
        {
            QAction *a = new QAction( qfu( p_parser->psz_longname ), menu );
            a->setCheckable( true );
            /* hack to handle submodules properly */
            int i = -1;
            while( p_parser->pp_shortcuts[++i] != NULL );
            i--;
            if( playlist_IsServicesDiscoveryLoaded( THEPL,
445 446
                        i>=0?p_parser->pp_shortcuts[i]
                        : p_parser->psz_object_name ) )
zorglub's avatar
zorglub committed
447 448 449 450 451
            {
                a->setChecked( true );
            }
            CONNECT( a , triggered(), THEDP->SDMapper, map() );
            THEDP->SDMapper->setMapping( a, i>=0? p_parser->pp_shortcuts[i] :
452
                    p_parser->psz_object_name );
zorglub's avatar
zorglub committed
453 454 455 456 457 458
            menu->addAction( a );
        }
    }
    vlc_list_release( p_list );
    return menu;
}
459 460 461
/**
 * Help/About Menu
**/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
462 463 464
QMenu *QVLCMenu::HelpMenu()
{
    QMenu *menu = new QMenu();
465 466
    DP_SADD( menu, qtr("Help") , "", ":/pixmaps/vlc_help_16px.png",
             helpDialog(), "F1" );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
467
    menu->addSeparator();
468
    DP_SADD( menu, qtr( I_MENU_ABOUT ), "", "", aboutDialog(), "Ctrl+F1");
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
469 470 471 472
    return menu;
}


473
/*****************************************************************************
474
 * Popup menus - Right Click menus                                           *
475
 *****************************************************************************/
zorglub's avatar
zorglub committed
476 477
#define POPUP_BOILERPLATE \
    unsigned int i_last_separator = 0; \
478 479 480 481 482 483 484 485 486
    vector<int> objects; \
    vector<const char *> varnames; \
    input_thread_t *p_input = THEMIM->getInput();

#define CREATE_POPUP \
    QMenu *menu = new QMenu(); \
    Populate( p_intf, menu, varnames, objects ); \
    p_intf->p_sys->p_popup_menu = menu; \
    menu->popup( QCursor::pos() ); \
zorglub's avatar
zorglub committed
487
    p_intf->p_sys->p_popup_menu = NULL; \
488
    i_last_separator = 0;
zorglub's avatar
zorglub committed
489

490
#define POPUP_PLAY_ENTRIES( menu )\
491 492
    vlc_value_t val; \
    if( p_input ) \
zorglub's avatar
zorglub committed
493 494
    { \
        var_Get( p_input, "state", &val ); \
495
        if( val.i_int == PLAYING_S ) \
496 497
            MIM_SADD( menu, qtr("Pause"), "", ":/pixmaps/vlc_pause_16px.png", \
                    togglePlayPause() ) \
498
        else \
499 500
            MIM_SADD( menu, qtr("Play"), "", ":/pixmaps/vlc_play_16px.png", \
                    togglePlayPause() ) \
zorglub's avatar
zorglub committed
501
    } \
zorglub's avatar
zorglub committed
502
    else if( THEPL->items.i_size && THEPL->i_enabled ) \
503 504
        MIM_SADD( menu, qtr("Play"), "", ":/pixmaps/vlc_play_16px.png", \
                togglePlayPause() ); \
505
    \
506
    MIM_SADD( menu, qtr("Stop"), "", ":/pixmaps/vlc_stop_16px.png", stop() ); \
507 508 509
    MIM_SADD( menu, qtr("Previous"), "", ":/pixmaps/vlc_previous_16px.png", \
            prev() ); \
    MIM_SADD( menu, qtr("Next"), "", ":/pixmaps/vlc_next_16px.png", next() );
510 511 512

#define POPUP_STATIC_ENTRIES \
    POPUP_PLAY_ENTRIES( menu ); \
zorglub's avatar
zorglub committed
513
    \
514
    menu->addSeparator(); \
515
    QMenu *intfmenu = InterfacesMenu( p_intf, NULL ); \
zorglub's avatar
zorglub committed
516
    intfmenu->setTitle( qtr("Interfaces" ) ); \
517 518
    menu->addMenu( intfmenu ); \
    \
519
    QMenu *toolsmenu = ToolsMenu( p_intf, NULL, false, false, false ); \
zorglub's avatar
zorglub committed
520
    toolsmenu->setTitle( qtr("Tools" ) ); \
521
    menu->addMenu( toolsmenu ); \
522 523 524 525 526 527 528 529 530 531 532 533 534 535
    \
    QMenu *openmenu = new QMenu( qtr("Open") ); \
    openmenu->addAction( qtr("Open &File..." ), THEDP, SLOT( openFileDialog() ) ); \
    openmenu->addAction( qtr("Open &Disc..." ), THEDP, SLOT( openDiscDialog() ) ); \
    openmenu->addAction( qtr("Open &Network..." ), THEDP, SLOT( openNetDialog() ) ); \
    openmenu->addAction( qtr("Open &Capture Device..." ), THEDP, \
            SLOT( openCaptureDialog() ) ); \
    menu->addMenu( openmenu ); \
    \
    menu->addSeparator(); \
    QMenu *helpmenu = HelpMenu(); \
    helpmenu->setTitle( qtr("Help") ); \
    menu->addMenu( helpmenu ); \
    \
536
    DP_SADD( menu, qtr("Quit"), "", "", quit() , "Ctrl+Q" );
zorglub's avatar
Qt4:  
zorglub committed
537

538
/* Video Tracks and Subtitles tracks */
539
void QVLCMenu::VideoPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
540 541 542 543 544
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
545 546 547 548
        varnames.push_back( "video-es" );
        objects.push_back( p_input->i_object_id );
        varnames.push_back( "spu-es" );
        objects.push_back( p_input->i_object_id );
zorglub's avatar
zorglub committed
549
        vlc_object_t *p_vout = (vlc_object_t *)vlc_object_find( p_input,
550
                VLC_OBJECT_VOUT, FIND_CHILD );
zorglub's avatar
zorglub committed
551 552
        if( p_vout )
        {
553
            VideoAutoMenuBuilder( p_vout, objects, varnames );
zorglub's avatar
zorglub committed
554 555 556 557
            vlc_object_release( p_vout );
        }
        vlc_object_release( p_input );
    }
558
    CREATE_POPUP;
zorglub's avatar
zorglub committed
559 560
}

561
/* Audio Tracks */
562
void QVLCMenu::AudioPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
563 564 565 566 567
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
568 569
        varnames.push_back( "audio-es" );
        objects.push_back( p_input->i_object_id );
zorglub's avatar
zorglub committed
570
        vlc_object_t *p_aout = (vlc_object_t *)vlc_object_find( p_input,
571
                VLC_OBJECT_AOUT, FIND_ANYWHERE );
zorglub's avatar
zorglub committed
572 573
        if( p_aout )
        {
574
            AudioAutoMenuBuilder( p_aout, objects, varnames );
zorglub's avatar
zorglub committed
575 576 577 578
            vlc_object_release( p_aout );
        }
        vlc_object_release( p_input );
    }
579
    CREATE_POPUP;
zorglub's avatar
zorglub committed
580 581
}

582
/* Navigation stuff, and general menus (open) */
583
void QVLCMenu::MiscPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
584 585 586 587 588
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
589 590
        varnames.push_back( "audio-es" );
        InputAutoMenuBuilder( VLC_OBJECT(p_input), objects, varnames );
zorglub's avatar
zorglub committed
591 592 593
        PUSH_SEPARATOR;
    }

594 595 596
    QMenu *menu = new QMenu();
    Populate( p_intf, menu, varnames, objects );
    menu->addSeparator();
zorglub's avatar
zorglub committed
597 598
    POPUP_STATIC_ENTRIES;

599 600
    p_intf->p_sys->p_popup_menu = menu;
    menu->popup( QCursor::pos() );
zorglub's avatar
zorglub committed
601 602 603
    p_intf->p_sys->p_popup_menu = NULL;
}

604
/* Main Menu that sticks everything together  */
damienf's avatar
damienf committed
605
void QVLCMenu::PopupMenu( intf_thread_t *p_intf, bool show )
zorglub's avatar
zorglub committed
606
{
damienf's avatar
damienf committed
607
    if( show )
zorglub's avatar
zorglub committed
608
    {
609
        // create a  popup if there is none
damienf's avatar
damienf committed
610
        if( ! p_intf->p_sys->p_popup_menu )
611
        {
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
            POPUP_BOILERPLATE;
            if( p_input )
            {
                vlc_object_yield( p_input );
                InputAutoMenuBuilder( VLC_OBJECT(p_input), objects, varnames );

                /* Video menu */
                PUSH_SEPARATOR;
                varnames.push_back( "video-es" );
                objects.push_back( p_input->i_object_id );
                varnames.push_back( "spu-es" );
                objects.push_back( p_input->i_object_id );
                vlc_object_t *p_vout = (vlc_object_t *)vlc_object_find( p_input,
                        VLC_OBJECT_VOUT, FIND_CHILD );
                if( p_vout )
                {
                    VideoAutoMenuBuilder( p_vout, objects, varnames );
                    vlc_object_release( p_vout );
                }
                /* Audio menu */
                PUSH_SEPARATOR
                    varnames.push_back( "audio-es" );
                objects.push_back( p_input->i_object_id );
                vlc_object_t *p_aout = (vlc_object_t *)vlc_object_find( p_input,
                        VLC_OBJECT_AOUT, FIND_ANYWHERE );
                if( p_aout )
                {
                    AudioAutoMenuBuilder( p_aout, objects, varnames );
                    vlc_object_release( p_aout );
                }
            }
643

644 645 646 647
            QMenu *menu = new QMenu();
            Populate( p_intf, menu, varnames, objects );
            menu->addSeparator();
            POPUP_STATIC_ENTRIES;
648

649 650 651
            p_intf->p_sys->p_popup_menu = menu;
        }
        p_intf->p_sys->p_popup_menu->popup( QCursor::pos() );
damienf's avatar
damienf committed
652 653
    }
    else
654
    {
655 656 657
        // destroy popup if there is one
        delete p_intf->p_sys->p_popup_menu;
        p_intf->p_sys->p_popup_menu = NULL;
zorglub's avatar
zorglub committed
658 659 660
    }
}

661 662 663 664
/************************************************************************
 * Systray Menu                                                         *
 ************************************************************************/

665 666 667
void QVLCMenu::updateSystrayMenu( MainInterface *mi,
                                  intf_thread_t *p_intf,
                                  bool b_force_visible )
668 669
{
    POPUP_BOILERPLATE;
670 671

    /* Get the systray menu and clean it */
672 673
    QMenu *sysMenu = mi->getSysTrayMenu();
    sysMenu->clear();
674 675

    /* Hide / Show VLC and cone */
676
    if( mi->isVisible() || b_force_visible )
677
    {
678 679
        sysMenu->addAction( QIcon( ":/vlc16.png" ),
                qtr("Hide VLC media player"), mi,
680
                SLOT( toggleUpdateSystrayMenu() ) );
681 682 683
    }
    else
    {
684 685
        sysMenu->addAction( QIcon( ":/vlc16.png" ),
                qtr("Show VLC media player"), mi,
686
                SLOT( toggleUpdateSystrayMenu() ) );
687
    }
688

689 690
    sysMenu->addSeparator();
    POPUP_PLAY_ENTRIES( sysMenu );
691

692
    sysMenu->addSeparator();
693 694
    DP_SADD( sysMenu, qtr("&Open Media" ), "",
            ":/pixmaps/vlc_file-wide_16px.png", openFileDialog(), "" );
695 696
    DP_SADD( sysMenu, qtr("&Quit") , "", ":/pixmaps/vlc_quit_16px.png",
             quit(), "" );
697

698
    /* Set the menu */
699 700 701
    mi->getSysTray()->setContextMenu( sysMenu );
}

702 703
#undef PUSH_VAR
#undef PUSH_SEPARATOR
zorglub's avatar
zorglub committed
704

705

706 707 708
/*************************************************************************
 * Builders for automenus
 *************************************************************************/
zorglub's avatar
zorglub committed
709
QMenu * QVLCMenu::Populate( intf_thread_t *p_intf, QMenu *current,
710 711
        vector< const char *> & varnames,
        vector<int> & objects, bool append )
zorglub's avatar
zorglub committed
712 713 714 715
{
    QMenu *menu = current;
    if( !menu )
        menu = new QMenu();
716
    else if( !append )
zorglub's avatar
zorglub committed
717 718 719 720 721 722 723 724
        menu->clear();

    currentGroup = NULL;

    vlc_object_t *p_object;
    vlc_bool_t b_section_empty = VLC_FALSE;
    int i;

zorglub's avatar
zorglub committed
725
#define APPEND_EMPTY { QAction *action = menu->addAction( qtr("Empty" ) ); \
726
    action->setEnabled( false ); }
zorglub's avatar
zorglub committed
727

728
    for( i = 0; i < (int)objects.size() ; i++ )
zorglub's avatar
zorglub committed
729
    {
730
        if( !varnames[i] || !*varnames[i] )
zorglub's avatar
zorglub committed
731 732 733 734 735 736 737 738
        {
            if( b_section_empty )
                APPEND_EMPTY;
            menu->addSeparator();
            b_section_empty = VLC_TRUE;
            continue;
        }

739
        if( objects[i] == 0  )
zorglub's avatar
zorglub committed
740 741
        {
            /// \bug What is this ?
742
            // Append( menu, varnames[i], NULL );
zorglub's avatar
zorglub committed
743 744 745 746 747
            b_section_empty = VLC_FALSE;
            continue;
        }

        p_object = (vlc_object_t *)vlc_object_get( p_intf,
748
                objects[i] );
zorglub's avatar
zorglub committed
749 750 751
        if( p_object == NULL ) continue;

        b_section_empty = VLC_FALSE;
752 753 754 755 756
        /* Ugly specific stuff */
        if( strstr(varnames[i], "intf-add" ) )
            CreateItem( menu, varnames[i], p_object, false );
        else
            CreateItem( menu, varnames[i], p_object, true );
zorglub's avatar
zorglub committed
757 758 759 760 761 762 763
        vlc_object_release( p_object );
    }

    /* Special case for empty menus */
    if( menu->actions().size() == 0 || b_section_empty )
        APPEND_EMPTY

764
            return menu;
zorglub's avatar
zorglub committed
765 766 767 768 769 770 771
}

/*****************************************************************************
 * Private methods.
 *****************************************************************************/

static bool IsMenuEmpty( const char *psz_var, vlc_object_t *p_object,
772
        bool b_root = TRUE )
zorglub's avatar
zorglub committed
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
{
    vlc_value_t val, val_list;
    int i_type, i_result, i;

    /* Check the type of the object variable */
    i_type = var_Type( p_object, psz_var );

    /* Check if we want to display the variable */
    if( !(i_type & VLC_VAR_HASCHOICE) ) return FALSE;

    var_Change( p_object, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
    if( val.i_int == 0 ) return TRUE;

    if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE )
    {
zorglub's avatar
zorglub committed
788
        /* Very evil hack ! intf-switch can have only one value */
zorglub's avatar
zorglub committed
789 790 791 792 793 794 795 796 797 798 799 800 801 802
        if( !strcmp( psz_var, "intf-switch" ) ) return FALSE;
        if( val.i_int == 1 && b_root ) return TRUE;
        else return FALSE;
    }

    /* Check children variables in case of VLC_VAR_VARIABLE */
    if( var_Change( p_object, psz_var, VLC_VAR_GETLIST, &val_list, NULL ) < 0 )
    {
        return TRUE;
    }

    for( i = 0, i_result = TRUE; i < val_list.p_list->i_count; i++ )
    {
        if( !IsMenuEmpty( val_list.p_list->p_values[i].psz_string,
803
                    p_object, FALSE ) )
zorglub's avatar
zorglub committed
804 805 806 807 808 809 810 811 812 813 814 815 816
        {
            i_result = FALSE;
            break;
        }
    }

    /* clean up everything */
    var_Change( p_object, psz_var, VLC_VAR_FREELIST, &val_list, NULL );

    return i_result;
}

void QVLCMenu::CreateItem( QMenu *menu, const char *psz_var,
817
        vlc_object_t *p_object, bool b_submenu )
zorglub's avatar
zorglub committed
818 819 820 821 822 823 824 825 826
{
    vlc_value_t val, text;
    int i_type;

    /* Check the type of the object variable */
    i_type = var_Type( p_object, psz_var );

    switch( i_type & VLC_VAR_TYPE )
    {
827 828 829 830 831 832 833 834 835 836
        case VLC_VAR_VOID:
        case VLC_VAR_BOOL:
        case VLC_VAR_VARIABLE:
        case VLC_VAR_STRING:
        case VLC_VAR_INTEGER:
        case VLC_VAR_FLOAT:
            break;
        default:
            /* Variable doesn't exist or isn't handled */
            return;
zorglub's avatar
zorglub committed
837 838 839 840 841 842 843 844 845 846 847
    }

    /* Make sure we want to display the variable */
    if( IsMenuEmpty( psz_var, p_object ) )  return;

    /* Get the descriptive name of the variable */
    var_Change( p_object, psz_var, VLC_VAR_GETTEXT, &text, NULL );

    if( i_type & VLC_VAR_HASCHOICE )
    {
        /* Append choices menu */
848 849 850
        if( b_submenu )
        {
            QMenu *submenu = new QMenu();
zorglub's avatar
Qt4:  
zorglub committed
851
            submenu->setTitle( qfu( text.psz_string ?
852
                        text.psz_string : psz_var ) );
853 854 855 856 857
            if( CreateChoicesMenu( submenu, psz_var, p_object, true ) == 0)
                menu->addMenu( submenu );
        }
        else
            CreateChoicesMenu( menu, psz_var, p_object, true );
858
        FREENULL( text.psz_string );
zorglub's avatar
zorglub committed
859 860 861
        return;
    }

862
#define TEXT_OR_VAR qfu ( text.psz_string ? text.psz_string : psz_var )
zorglub's avatar
zorglub committed
863 864 865

    switch( i_type & VLC_VAR_TYPE )
    {
866 867 868 869 870 871 872 873 874 875 876 877
        case VLC_VAR_VOID:
            var_Get( p_object, psz_var, &val );
            CreateAndConnect( menu, psz_var, TEXT_OR_VAR, "", ITEM_NORMAL,
                    p_object->i_object_id, val, i_type );
            break;

        case VLC_VAR_BOOL:
            var_Get( p_object, psz_var, &val );
            val.b_bool = !val.b_bool;
            CreateAndConnect( menu, psz_var, TEXT_OR_VAR, "", ITEM_CHECK,
                    p_object->i_object_id, val, i_type, !val.b_bool );
            break;
zorglub's avatar
zorglub committed
878
    }
879
    FREENULL( text.psz_string );
zorglub's avatar
zorglub committed
880 881 882
}


zorglub's avatar
zorglub committed
883
int QVLCMenu::CreateChoicesMenu( QMenu *submenu, const char *psz_var,
884
        vlc_object_t *p_object, bool b_root )
zorglub's avatar
zorglub committed
885 886 887 888 889 890 891 892
{
    vlc_value_t val, val_list, text_list;
    int i_type, i;

    /* Check the type of the object variable */
    i_type = var_Type( p_object, psz_var );

    /* Make sure we want to display the variable */
893
    if( IsMenuEmpty( psz_var, p_object, b_root ) ) return VLC_EGENERIC;
zorglub's avatar
zorglub committed
894 895 896

    switch( i_type & VLC_VAR_TYPE )
    {
897 898 899 900 901 902 903 904 905 906
        case VLC_VAR_VOID:
        case VLC_VAR_BOOL:
        case VLC_VAR_VARIABLE:
        case VLC_VAR_STRING:
        case VLC_VAR_INTEGER:
        case VLC_VAR_FLOAT:
            break;
        default:
            /* Variable doesn't exist or isn't handled */
            return VLC_EGENERIC;
zorglub's avatar
zorglub committed
907 908 909
    }

    if( var_Change( p_object, psz_var, VLC_VAR_GETLIST,
910
                &val_list, &text_list ) < 0 )
zorglub's avatar
zorglub committed
911
    {
912
        return VLC_EGENERIC;
zorglub's avatar
zorglub committed
913 914
    }
#define NORMAL_OR_RADIO i_type & VLC_VAR_ISCOMMAND ? ITEM_NORMAL: ITEM_RADIO
zorglub's avatar
Qt4:  
zorglub committed
915
#define NOTCOMMAND !(i_type & VLC_VAR_ISCOMMAND)
zorglub's avatar
zorglub committed
916 917 918 919 920 921 922
#define CURVAL val_list.p_list->p_values[i]
#define CURTEXT text_list.p_list->p_values[i].psz_string

    for( i = 0; i < val_list.p_list->i_count; i++ )
    {
        vlc_value_t another_val;
        QString menutext;
923
        QMenu *subsubmenu = new QMenu();
zorglub's avatar
zorglub committed
924 925 926

        switch( i_type & VLC_VAR_TYPE )
        {
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959