hotkeys.c 53.9 KB
Newer Older
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
1 2 3
/*****************************************************************************
 * hotkeys.c: Hotkey handling for vlc
 *****************************************************************************
4
 * Copyright (C) 2005-2009 the VideoLAN team
5
 * $Id$
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
6
 *
7
 * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
8
 *          Jean-Paul Saman <jpsaman #_at_# m2x.nl>
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
9 10 11 12 13
 *
 * 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.
14
 *
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
15 16 17 18 19 20 21
 * 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
Antoine Cellerier's avatar
Antoine Cellerier committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
23 24 25 26 27 28
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

29 30 31 32
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

33
#define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
34
#include <vlc_common.h>
35
#include <vlc_plugin.h>
36 37
#include <vlc_interface.h>
#include <vlc_input.h>
38
#include <vlc_aout.h>
39
#include <vlc_mouse.h>
40
#include <vlc_viewpoint.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
41
#include <vlc_vout_osd.h>
42
#include <vlc_playlist.h>
43
#include <vlc_actions.h>
44
#include "math.h"
45

46 47
#include <assert.h>

Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
48 49 50 51 52
/*****************************************************************************
 * intf_sys_t: description and status of FB interface
 *****************************************************************************/
struct intf_sys_t
{
53 54 55
    vlc_mutex_t         lock;
    vout_thread_t      *p_vout;
    input_thread_t     *p_input;
56
    int slider_chan;
57 58 59 60 61 62 63

    /*subtitle_delaybookmarks: placeholder for storing subtitle sync timestamps*/
    struct
    {
        int64_t i_time_subtitle;
        int64_t i_time_audio;
    } subtitle_delaybookmarks;
64 65 66 67 68 69 70

    struct
    {
        bool b_can_change;
        bool b_button_pressed;
        int x, y;
    } vrnav;
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
71 72 73 74 75 76 77
};

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int  Open    ( vlc_object_t * );
static void Close   ( vlc_object_t * );
78 79
static int  ActionEvent( vlc_object_t *, char const *,
                         vlc_value_t, vlc_value_t, void * );
80 81
static void PlayBookmark( intf_thread_t *, int );
static void SetBookmark ( intf_thread_t *, int );
82 83
static void DisplayPosition( vout_thread_t *, int,  input_thread_t * );
static void DisplayVolume( vout_thread_t *, int, float );
84
static void DisplayRate ( vout_thread_t *, float );
85
static float AdjustRateFine( vlc_object_t *, const int );
86
static void ClearChannels  ( vout_thread_t *, int );
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
87

88 89 90
#define DisplayMessage(vout, ...) \
    do { \
        if (vout) \
91
            vout_OSDMessage(vout, VOUT_SPU_CHANNEL_OSD, __VA_ARGS__); \
92
    } while(0)
93
#define DisplayIcon(vout, icon) \
94
    do { if(vout) vout_OSDIcon(vout, VOUT_SPU_CHANNEL_OSD, icon); } while(0)
95

Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
96 97 98
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
99

100 101 102 103 104
vlc_module_begin ()
    set_shortname( N_("Hotkeys") )
    set_description( N_("Hotkeys management interface") )
    set_capability( "interface", 0 )
    set_callbacks( Open, Close )
105 106
    set_category( CAT_INTERFACE )
    set_subcategory( SUBCAT_INTERFACE_HOTKEYS )
107

108
vlc_module_end ()
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
109

110 111 112 113 114 115 116 117 118 119 120 121 122 123
static int MovedEvent( vlc_object_t *p_this, char const *psz_var,
                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    intf_thread_t *p_intf = (intf_thread_t *)p_data;
    intf_sys_t    *p_sys = p_intf->p_sys;

    (void) p_this; (void) psz_var; (void) oldval;

    if( p_sys->vrnav.b_button_pressed )
    {
        int i_horizontal = newval.coords.x - p_sys->vrnav.x;
        int i_vertical   = newval.coords.y - p_sys->vrnav.y;

        vlc_viewpoint_t viewpoint = {
124 125
            .yaw   = -i_horizontal * 0.05f,
            .pitch = -i_vertical   * 0.05f,
126 127 128 129 130 131 132 133 134 135 136
        };

        input_UpdateViewpoint( p_sys->p_input, &viewpoint, false );

        p_sys->vrnav.x = newval.coords.x;
        p_sys->vrnav.y = newval.coords.y;
    }

    return VLC_SUCCESS;
}

137
static int ViewpointMovedEvent( vlc_object_t *p_this, char const *psz_var,
138 139
                                vlc_value_t oldval, vlc_value_t newval,
                                void *p_data )
140 141 142 143
{
    intf_thread_t *p_intf = (intf_thread_t *)p_data;
    intf_sys_t    *p_sys = p_intf->p_sys;

144 145
    (void) p_this; (void) psz_var; (void) oldval;

146 147 148 149 150
    input_UpdateViewpoint( p_sys->p_input, newval.p_address, false );

    return VLC_SUCCESS;
}

151 152 153 154 155 156
static int ButtonEvent( vlc_object_t *p_this, char const *psz_var,
                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    intf_thread_t *p_intf = p_data;
    intf_sys_t *p_sys = p_intf->p_sys;

157
    (void) psz_var;
158

159
    if ((newval.i_int & (1 << MOUSE_BUTTON_LEFT)) && p_sys->vrnav.b_can_change)
160 161 162 163 164 165 166 167 168 169 170
    {
        if( !p_sys->vrnav.b_button_pressed )
        {
            p_sys->vrnav.b_button_pressed = true;
            var_GetCoords( p_this, "mouse-moved",
                           &p_sys->vrnav.x, &p_sys->vrnav.y );
        }
    }
    else
        p_sys->vrnav.b_button_pressed = false;

171
    unsigned pressed = newval.i_int & ~oldval.i_int;
172

173 174 175
    if (pressed & (1 << MOUSE_BUTTON_LEFT))
        var_SetBool(pl_Get(p_intf), "intf-popupmenu", false);
    if (pressed & (1 << MOUSE_BUTTON_CENTER))
176
        var_TriggerCallback(pl_Get(p_intf), "intf-toggle-fscontrol");
177
#ifndef _WIN32
178
    if (pressed & (1 << MOUSE_BUTTON_RIGHT))
179 180 181 182
#else
    if ((oldval.i_int & (1 << MOUSE_BUTTON_RIGHT))
     && !(newval.i_int & (1 << MOUSE_BUTTON_RIGHT)))
#endif
183
        var_SetBool(pl_Get(p_intf), "intf-popupmenu", true);
184

185 186 187 188 189
    for (int i = MOUSE_BUTTON_WHEEL_UP; i <= MOUSE_BUTTON_WHEEL_RIGHT; i++)
        if (pressed & (1 << i))
            var_SetInteger(p_intf->obj.libvlc, "key-pressed",
                           i - MOUSE_BUTTON_WHEEL_UP + KEY_MOUSEWHEELUP);

190 191 192
    return VLC_SUCCESS;
}

193 194 195 196 197
static void ChangeVout( intf_thread_t *p_intf, vout_thread_t *p_vout )
{
    intf_sys_t *p_sys = p_intf->p_sys;

    int slider_chan;
198
    bool b_vrnav_can_change;
199
    if( p_vout != NULL )
200
    {
201
        slider_chan = vout_RegisterSubpictureChannel( p_vout );
202 203
        b_vrnav_can_change = var_GetBool( p_vout, "viewpoint-changeable" );
    }
204 205

    vout_thread_t *p_old_vout = p_sys->p_vout;
206 207 208 209 210
    if( p_old_vout != NULL && p_sys->vrnav.b_can_change )
        var_DelCallback( p_old_vout, "viewpoint-moved", ViewpointMovedEvent,
                         p_intf );

    vlc_mutex_lock( &p_sys->lock );
211 212
    p_sys->p_vout = p_vout;
    if( p_vout != NULL )
213
    {
214
        p_sys->slider_chan = slider_chan;
215 216 217 218
        p_sys->vrnav.b_can_change = b_vrnav_can_change;
    }
    else
        p_sys->vrnav.b_can_change = false;
219 220 221
    vlc_mutex_unlock( &p_sys->lock );

    if( p_old_vout != NULL )
222
    {
223 224 225
        var_DelCallback( p_old_vout, "mouse-button-down", ButtonEvent,
                         p_intf );
        var_DelCallback( p_old_vout, "mouse-moved", MovedEvent, p_intf );
226
        vlc_object_release( p_old_vout );
227 228
    }

229
    if( p_vout != NULL )
230
    {
231 232 233 234 235 236
        var_AddCallback( p_vout, "mouse-moved", MovedEvent, p_intf );
        var_AddCallback( p_vout, "mouse-button-down", ButtonEvent, p_intf );

        if( p_sys->vrnav.b_can_change )
            var_AddCallback( p_vout, "viewpoint-moved",
                             ViewpointMovedEvent, p_intf );
237
    }
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
}

static int InputEvent( vlc_object_t *p_this, char const *psz_var,
                       vlc_value_t oldval, vlc_value_t val, void *p_data )
{
    input_thread_t *p_input = (input_thread_t *)p_this;
    intf_thread_t *p_intf = p_data;

    (void) psz_var; (void) oldval;

    if( val.i_int == INPUT_EVENT_VOUT )
        ChangeVout( p_intf, input_GetVout( p_input ) );

    return VLC_SUCCESS;
}

static void ChangeInput( intf_thread_t *p_intf, input_thread_t *p_input )
{
    intf_sys_t *p_sys = p_intf->p_sys;

    input_thread_t *p_old_input = p_sys->p_input;
259
    vout_thread_t *p_old_vout = NULL;
260 261 262 263 264
    if( p_old_input != NULL )
    {
        /* First, remove callbacks from previous input. It's safe to access it
         * unlocked, since it's written from this thread */
        var_DelCallback( p_old_input, "intf-event", InputEvent, p_intf );
265 266 267 268

        p_old_vout = p_sys->p_vout;
        /* Remove mouse events before setting new input, since callbacks may
         * access it */
269
        if( p_old_vout != NULL )
270
        {
271 272 273 274
            if( p_sys->vrnav.b_can_change )
                var_DelCallback( p_old_vout, "viewpoint-moved",
                                 ViewpointMovedEvent, p_intf );

275
            var_DelCallback( p_old_vout, "mouse-button-down", ButtonEvent,
276
                             p_intf );
277
            var_DelCallback( p_old_vout, "mouse-moved", MovedEvent,
278 279
                             p_intf );
        }
280 281 282 283 284 285
    }

    /* Replace input and vout locked */
    vlc_mutex_lock( &p_sys->lock );
    p_sys->p_input = p_input ? vlc_object_hold( p_input ) : NULL;
    p_sys->p_vout = NULL;
286
    p_sys->vrnav.b_can_change = false;
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
    vlc_mutex_unlock( &p_sys->lock );

    /* Release old input and vout objects unlocked */
    if( p_old_input != NULL )
    {
        if( p_old_vout != NULL )
            vlc_object_release( p_old_vout );
        vlc_object_release( p_old_input );
    }

    /* Register input events */
    if( p_input != NULL )
        var_AddCallback( p_input, "intf-event", InputEvent, p_intf );
}

static int PlaylistEvent( vlc_object_t *p_this, char const *psz_var,
                          vlc_value_t oldval, vlc_value_t val, void *p_data )
{
    intf_thread_t *p_intf = p_data;

    (void) p_this; (void) psz_var; (void) oldval;

    ChangeInput( p_intf, val.p_address );

    return VLC_SUCCESS;
}

Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
314 315 316 317 318 319
/*****************************************************************************
 * Open: initialize interface
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
    intf_thread_t *p_intf = (intf_thread_t *)p_this;
320
    intf_sys_t *p_sys;
321 322 323
    p_sys = malloc( sizeof( intf_sys_t ) );
    if( !p_sys )
        return VLC_ENOMEM;
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
324

325
    p_intf->p_sys = p_sys;
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
326

327 328
    p_sys->p_vout = NULL;
    p_sys->p_input = NULL;
329 330
    p_sys->vrnav.b_can_change = false;
    p_sys->vrnav.b_button_pressed = false;
331 332
    p_sys->subtitle_delaybookmarks.i_time_audio = 0;
    p_sys->subtitle_delaybookmarks.i_time_subtitle = 0;
333

334 335
    vlc_mutex_init( &p_sys->lock );

336
    var_AddCallback( p_intf->obj.libvlc, "key-action", ActionEvent, p_intf );
337 338 339

    var_AddCallback( pl_Get(p_intf), "input-current", PlaylistEvent, p_intf );

340
    return VLC_SUCCESS;
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
341 342 343 344 345 346 347 348
}

/*****************************************************************************
 * Close: destroy interface
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
    intf_thread_t *p_intf = (intf_thread_t *)p_this;
349
    intf_sys_t *p_sys = p_intf->p_sys;
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
350

351 352
    var_DelCallback( pl_Get(p_intf), "input-current", PlaylistEvent, p_intf );

353
    var_DelCallback( p_intf->obj.libvlc, "key-action", ActionEvent, p_intf );
354

355 356 357 358
    ChangeInput( p_intf, NULL );

    vlc_mutex_destroy( &p_sys->lock );

Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
359
    /* Destroy structure */
360
    free( p_sys );
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
361 362
}

363
static int PutAction( intf_thread_t *p_intf, input_thread_t *p_input,
364 365
                      vout_thread_t *p_vout, int slider_chan, bool b_vrnav,
                      int i_action )
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
366
{
367
#define DO_ACTION(x) PutAction( p_intf, p_input, p_vout, slider_chan, b_vrnav, x)
368
    intf_sys_t *p_sys = p_intf->p_sys;
369
    playlist_t *p_playlist = pl_Get( p_intf );
370

371 372 373
    /* Quit */
    switch( i_action )
    {
374
        /* Libvlc / interface actions */
375
        case ACTIONID_QUIT:
376
            libvlc_Quit( p_intf->obj.libvlc );
377

378
            ClearChannels( p_vout, slider_chan );
379
            DisplayMessage( p_vout, _( "Quit" ) );
380 381
            break;

382
        case ACTIONID_INTF_TOGGLE_FSC:
383
        case ACTIONID_INTF_HIDE:
384
            var_TriggerCallback( p_playlist, "intf-toggle-fscontrol" );
385
            break;
386
        case ACTIONID_INTF_BOSS:
387
            var_TriggerCallback( p_playlist, "intf-boss" );
388
            break;
389
        case ACTIONID_INTF_POPUP_MENU:
390
            var_TriggerCallback( p_playlist, "intf-popupmenu" );
391
            break;
392

393
        /* Playlist actions (including audio) */
394
        case ACTIONID_LOOP:
395
        {
396
            /* Toggle Normal -> Loop -> Repeat -> Normal ... */
397
            const char *mode;
398
            if( var_GetBool( p_playlist, "repeat" ) )
399
            {
400
                var_SetBool( p_playlist, "repeat", false );
401 402
                mode = N_("Off");
            }
403
            else
404 405 406 407
            if( var_GetBool( p_playlist, "loop" ) )
            { /* FIXME: this is not atomic, we should use a real tristate */
                var_SetBool( p_playlist, "loop", false );
                var_SetBool( p_playlist, "repeat", true );
408
                mode = N_("One");
409
            }
410
            else
411
            {
412
                var_SetBool( p_playlist, "loop", true );
413 414 415
                mode = N_("All");
            }
            DisplayMessage( p_vout, _("Loop: %s"), vlc_gettext(mode) );
416
            break;
417
        }
418 419

        case ACTIONID_RANDOM:
420 421 422 423
        {
            const bool state = var_ToggleBool( p_playlist, "random" );
            DisplayMessage( p_vout, _("Random: %s"),
                            vlc_gettext( state ? N_("On") : N_("Off") ) );
424
            break;
425
        }
426 427

        case ACTIONID_NEXT:
428
            DisplayMessage( p_vout, _("Next") );
429 430 431
            playlist_Next( p_playlist );
            break;
        case ACTIONID_PREV:
432
            DisplayMessage( p_vout, _("Previous") );
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
            playlist_Prev( p_playlist );
            break;

        case ACTIONID_STOP:
            playlist_Stop( p_playlist );
            break;

        case ACTIONID_RATE_NORMAL:
            var_SetFloat( p_playlist, "rate", 1.f );
            DisplayRate( p_vout, 1.f );
            break;
        case ACTIONID_FASTER:
            var_TriggerCallback( p_playlist, "rate-faster" );
            DisplayRate( p_vout, var_GetFloat( p_playlist, "rate" ) );
            break;
        case ACTIONID_SLOWER:
            var_TriggerCallback( p_playlist, "rate-slower" );
            DisplayRate( p_vout, var_GetFloat( p_playlist, "rate" ) );
            break;
        case ACTIONID_RATE_FASTER_FINE:
        case ACTIONID_RATE_SLOWER_FINE:
        {
            const int i_dir = i_action == ACTIONID_RATE_FASTER_FINE ? 1 : -1;
            float rate = AdjustRateFine( VLC_OBJECT(p_playlist), i_dir );

            var_SetFloat( p_playlist, "rate", rate );
            DisplayRate( p_vout, rate );
            break;
461
        }
462

463 464 465 466 467 468 469 470 471 472 473 474
        case ACTIONID_PLAY_BOOKMARK1:
        case ACTIONID_PLAY_BOOKMARK2:
        case ACTIONID_PLAY_BOOKMARK3:
        case ACTIONID_PLAY_BOOKMARK4:
        case ACTIONID_PLAY_BOOKMARK5:
        case ACTIONID_PLAY_BOOKMARK6:
        case ACTIONID_PLAY_BOOKMARK7:
        case ACTIONID_PLAY_BOOKMARK8:
        case ACTIONID_PLAY_BOOKMARK9:
        case ACTIONID_PLAY_BOOKMARK10:
            PlayBookmark( p_intf, i_action - ACTIONID_PLAY_BOOKMARK1 + 1 );
            break;
475

476 477 478 479 480 481 482 483 484 485 486
        case ACTIONID_SET_BOOKMARK1:
        case ACTIONID_SET_BOOKMARK2:
        case ACTIONID_SET_BOOKMARK3:
        case ACTIONID_SET_BOOKMARK4:
        case ACTIONID_SET_BOOKMARK5:
        case ACTIONID_SET_BOOKMARK6:
        case ACTIONID_SET_BOOKMARK7:
        case ACTIONID_SET_BOOKMARK8:
        case ACTIONID_SET_BOOKMARK9:
        case ACTIONID_SET_BOOKMARK10:
            SetBookmark( p_intf, i_action - ACTIONID_SET_BOOKMARK1 + 1 );
487
            break;
488 489 490
        case ACTIONID_PLAY_CLEAR:
            playlist_Clear( p_playlist, pl_Unlocked );
            break;
491 492 493 494
        case ACTIONID_VOL_UP:
        {
            float vol;
            if( playlist_VolumeUp( p_playlist, 1, &vol ) == 0 )
495
                DisplayVolume( p_vout, slider_chan, vol );
496 497 498 499 500 501
            break;
        }
        case ACTIONID_VOL_DOWN:
        {
            float vol;
            if( playlist_VolumeDown( p_playlist, 1, &vol ) == 0 )
502
                DisplayVolume( p_vout, slider_chan, vol );
503 504 505
            break;
        }
        case ACTIONID_VOL_MUTE:
506 507 508 509 510 511 512 513 514 515
        {
            int mute = playlist_MuteGet( p_playlist );
            if( mute < 0 )
                break;
            mute = !mute;
            if( playlist_MuteSet( p_playlist, mute ) )
                break;

            float vol = playlist_VolumeGet( p_playlist );
            if( mute || vol == 0.f )
516
            {
517
                ClearChannels( p_vout, slider_chan );
518
                DisplayIcon( p_vout, OSD_MUTE_ICON );
519
            }
520
            else
521
                DisplayVolume( p_vout, slider_chan, vol );
522
            break;
523
        }
524

525
        case ACTIONID_AUDIODEVICE_CYCLE:
526
        {
527
            audio_output_t *p_aout = playlist_GetAout( p_playlist );
528
            if( p_aout == NULL )
529 530
                break;

531 532 533 534
            char **ids, **names;
            int n = aout_DevicesList( p_aout, &ids, &names );
            if( n == -1 )
                break;
535

536 537
            char *dev = aout_DeviceGet( p_aout );
            const char *devstr = (dev != NULL) ? dev : "";
538

539 540 541 542 543 544
            int idx = 0;
            for( int i = 0; i < n; i++ )
            {
                if( !strcmp(devstr, ids[i]) )
                    idx = (i + 1) % n;
            }
545 546
            free( dev );

547
            if( !aout_DeviceSet( p_aout, ids[idx] ) )
548
                DisplayMessage( p_vout, _("Audio Device: %s"), names[idx] );
549
            vlc_object_release( p_aout );
550 551 552 553 554 555 556 557

            for( int i = 0; i < n; i++ )
            {
                free( ids[i] );
                free( names[i] );
            }
            free( ids );
            free( names );
558
            break;
559
        }
560

561 562 563
        /* Playlist + input actions */
        case ACTIONID_PLAY_PAUSE:
            if( p_input )
564
            {
565
                ClearChannels( p_vout, slider_chan );
566 567 568

                int state = var_GetInteger( p_input, "state" );
                DisplayIcon( p_vout, state != PAUSE_S ? OSD_PAUSE_ICON : OSD_PLAY_ICON );
569
            }
570
            playlist_TogglePause( p_playlist );
571 572 573
            break;

        case ACTIONID_PLAY:
574
            if( p_input && var_GetFloat( p_input, "rate" ) != 1.f )
575
                /* Return to normal speed */
576
                var_SetFloat( p_input, "rate", 1.f );
577
            else
578
            {
579
                ClearChannels( p_vout, slider_chan );
580 581
                DisplayIcon( p_vout, OSD_PLAY_ICON );
                playlist_Play( p_playlist );
582
            }
583 584 585 586
            break;

        /* Playlist + video output actions */
        case ACTIONID_WALLPAPER:
587 588 589 590
        {
            bool wp = var_ToggleBool( p_playlist, "video-wallpaper" );
            if( p_vout )
                var_SetBool( p_vout, "video-wallpaper", wp );
591 592 593 594 595 596
            break;
        }

        /* Input actions */
        case ACTIONID_PAUSE:
            if( p_input && var_GetInteger( p_input, "state" ) != PAUSE_S )
597
            {
598
                ClearChannels( p_vout, slider_chan );
599 600
                DisplayIcon( p_vout, OSD_PAUSE_ICON );
                var_SetInteger( p_input, "state", PAUSE_S );
601
            }
602 603 604 605
            break;

        case ACTIONID_RECORD:
            if( p_input && var_GetBool( p_input, "can-record" ) )
606
            {
607
                const bool on = var_ToggleBool( p_input, "record" );
608 609
                DisplayMessage( p_vout, vlc_gettext(on
                                   ? N_("Recording") : N_("Recording done")) );
610
            }
611 612 613 614
            break;

        case ACTIONID_FRAME_NEXT:
            if( p_input )
615
            {
616
                var_TriggerCallback( p_input, "frame-next" );
617
                DisplayMessage( p_vout, _("Next frame") );
618
            }
619 620
            break;

621 622 623
        case ACTIONID_SUBSYNC_MARKAUDIO:
        {
            p_sys->subtitle_delaybookmarks.i_time_audio = mdate();
624
            DisplayMessage( p_vout, _("Sub sync: bookmarked audio time"));
625 626 627
            break;
        }
        case ACTIONID_SUBSYNC_MARKSUB:
628 629
            if( p_input )
            {
630 631
                vlc_value_t val;
                vlc_list_t list, list2;
632

633
                var_Get( p_input, "spu-es", &val );
634 635
                var_Change( p_input, "spu-es", VLC_VAR_GETCHOICES,
                            &list, &list2 );
636 637

                if( list.i_count < 1 || val.i_int < 0 )
638
                {
639
                    DisplayMessage( p_vout, _("No active subtitle") );
640 641 642 643 644
                    var_FreeList( &list, &list2 );
                    break;
                }
                p_sys->subtitle_delaybookmarks.i_time_subtitle = mdate();
                DisplayMessage( p_vout,
645
                                _("Sub sync: bookmarked subtitle time"));
646 647
                var_FreeList( &list, &list2 );
            }
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
            break;
        case ACTIONID_SUBSYNC_APPLY:
        {
            /* Warning! Can yield a pause in the playback.
             * For example, the following succession of actions will yield a 5 second delay :
             * - Pressing Shift-H (ACTIONID_SUBSYNC_MARKAUDIO)
             * - wait 5 second
             * - Press Shift-J (ACTIONID_SUBSYNC_MARKSUB)
             * - Press Shift-K (ACTIONID_SUBSYNC_APPLY)
             * --> 5 seconds pause
             * This is due to var_SetTime() (and ultimately UpdatePtsDelay())
             * which causes the video to pause for an equivalent duration
             * (This problem is also present in the "Track synchronization" window) */
            if ( p_input )
            {
                if ( (p_sys->subtitle_delaybookmarks.i_time_audio == 0) || (p_sys->subtitle_delaybookmarks.i_time_subtitle == 0) )
                {
                    DisplayMessage( p_vout, _( "Sub sync: set bookmarks first!" ) );
                }
                else
                {
669
                    int64_t i_current_subdelay = var_GetInteger( p_input, "spu-delay" );
670 671
                    int64_t i_additional_subdelay = p_sys->subtitle_delaybookmarks.i_time_audio - p_sys->subtitle_delaybookmarks.i_time_subtitle;
                    int64_t i_total_subdelay = i_current_subdelay + i_additional_subdelay;
672
                    var_SetInteger( p_input, "spu-delay", i_total_subdelay);
673
                    ClearChannels( p_vout, slider_chan );
674 675 676 677 678 679 680 681 682 683 684
                    DisplayMessage( p_vout, _( "Sub sync: corrected %i ms (total delay = %i ms)" ),
                                            (int)(i_additional_subdelay / 1000),
                                            (int)(i_total_subdelay / 1000) );
                    p_sys->subtitle_delaybookmarks.i_time_audio = 0;
                    p_sys->subtitle_delaybookmarks.i_time_subtitle = 0;
                }
            }
            break;
        }
        case ACTIONID_SUBSYNC_RESET:
        {
685
            var_SetInteger( p_input, "spu-delay", 0);
686
            ClearChannels( p_vout, slider_chan );
687 688 689 690 691 692
            DisplayMessage( p_vout, _( "Sub sync: delay reset" ) );
            p_sys->subtitle_delaybookmarks.i_time_audio = 0;
            p_sys->subtitle_delaybookmarks.i_time_subtitle = 0;
            break;
        }

693 694 695 696 697
        case ACTIONID_SUBDELAY_DOWN:
        case ACTIONID_SUBDELAY_UP:
        {
            int diff = (i_action == ACTIONID_SUBDELAY_UP) ? 50000 : -50000;
            if( p_input )
698
            {
699 700
                vlc_value_t val;
                vlc_list_t list, list2;
701

702
                var_Get( p_input, "spu-es", &val );
703 704
                var_Change( p_input, "spu-es", VLC_VAR_GETCHOICES,
                            &list, &list2 );
705 706

                if( list.i_count < 1 || val.i_int < 0 )
707
                {
708
                    DisplayMessage( p_vout, _("No active subtitle") );
709 710 711
                    var_FreeList( &list, &list2 );
                    break;
                }
712
                int64_t i_delay = var_GetInteger( p_input, "spu-delay" ) + diff;
713

714
                var_SetInteger( p_input, "spu-delay", i_delay );
715
                ClearChannels( p_vout, slider_chan );
716
                DisplayMessage( p_vout, _( "Subtitle delay %i ms" ),
717
                                (int)(i_delay/1000) );
718
                var_FreeList( &list, &list2 );
719
            }
720 721 722 723 724 725 726
            break;
        }
        case ACTIONID_AUDIODELAY_DOWN:
        case ACTIONID_AUDIODELAY_UP:
        {
            int diff = (i_action == ACTIONID_AUDIODELAY_UP) ? 50000 : -50000;
            if( p_input )
727
            {
728 729
                int64_t i_delay = var_GetInteger( p_input, "audio-delay" )
                                  + diff;
730

731
                var_SetInteger( p_input, "audio-delay", i_delay );
732
                ClearChannels( p_vout, slider_chan );
733
                DisplayMessage( p_vout, _( "Audio delay %i ms" ),
734
                                 (int)(i_delay/1000) );
735
            }
736 737 738 739 740
            break;
        }

        case ACTIONID_AUDIO_TRACK:
            if( p_input )
741
            {
742 743 744
                vlc_value_t val;
                vlc_list_t list, list2;

745 746 747
                var_Get( p_input, "audio-es", &val );
                var_Change( p_input, "audio-es", VLC_VAR_GETCHOICES,
                            &list, &list2 );
748 749

                if( list.i_count > 1 )
750
                {
751 752 753
                    int i;

                    for( i = 0; i < list.i_count; i++ )
754
                    {
755
                        if( val.i_int == list.p_values[i].i_int )
756 757 758
                        {
                            break;
                        }
759
                    }
760
                    /* value of audio-es was not in choices list */
761
                    if( i == list.i_count )
762 763 764 765 766
                    {
                        msg_Warn( p_input,
                                  "invalid current audio track, selecting 0" );
                        i = 0;
                    }
767
                    else if( i == list.i_count - 1 )
768 769 770
                        i = 1;
                    else
                        i++;
771
                    var_Set( p_input, "audio-es", list.p_values[i] );
772
                    DisplayMessage( p_vout, _("Audio track: %s"),
773
                                    list2.p_values[i].psz_string );
774
                }
775
                var_FreeList( &list, &list2 );
776
            }
777
            break;
778

779
        case ACTIONID_SUBTITLE_TRACK:
780
        case ACTIONID_SUBTITLE_REVERSE_TRACK:
781
            if( p_input )
782
            {
783 784 785
                vlc_value_t val;
                vlc_list_t list, list2;
                int i;
786
                var_Get( p_input, "spu-es", &val );
787

788 789
                var_Change( p_input, "spu-es", VLC_VAR_GETCHOICES,
                            &list, &list2 );
790 791

                if( list.i_count <= 1 )
792
                {
793 794
                    DisplayMessage( p_vout, _("Subtitle track: %s"),
                                    _("N/A") );
795
                    var_FreeList( &list, &list2 );
796
                    break;
797
                }
798
                for( i = 0; i < list.i_count; i++ )
799
                {
800
                    if( val.i_int == list.p_values[i].i_int )
801 802 803 804
                    {
                        break;
                    }
                }
805
                /* value of spu-es was not in choices list */
806
                if( i == list.i_count )
807
                {
808 809
                    msg_Warn( p_input,
                              "invalid current subtitle track, selecting 0" );
810 811
                    i = 0;
                }
812
                else if ((i == list.i_count - 1) && (i_action == ACTIONID_SUBTITLE_TRACK))
813
                    i = 0;
814
                else if ((i == 0) && (i_action == ACTIONID_SUBTITLE_REVERSE_TRACK))
815
                    i = list.i_count - 1;
816
                else
817
                    i = (i_action == ACTIONID_SUBTITLE_TRACK) ? i+1 : i-1;
818
                var_SetInteger( p_input, "spu-es", list.p_values[i].i_int );
819
                DisplayMessage( p_vout, _("Subtitle track: %s"),
820
                                list2.p_values[i].psz_string );
821
                var_FreeList( &list, &list2 );
822
            }
823 824 825 826
            break;
        case ACTIONID_SUBTITLE_TOGGLE:
            if( p_input )
            {
827 828
                vlc_list_t list, list2;

829 830
                var_Change( p_input, "spu-es", VLC_VAR_GETCHOICES,
                            &list, &list2 );
831 832

                if( list.i_count <= 1 )
833 834 835 836 837 838
                {
                    DisplayMessage( p_vout, _("Subtitle track: %s"),
                                    _("N/A") );
                    var_FreeList( &list, &list2 );
                    break;
                }
839 840 841 842

                int i_cur_id = var_GetInteger( p_input, "spu-es" );
                int i_new_id;
                if( i_cur_id == -1 )
843
                {
844 845 846 847
                    /* subtitles were disabled: restore the saved track id */
                    i_new_id = var_GetInteger( p_input, "spu-choice" );
                    if( i_new_id != -1 )
                        var_SetInteger( p_input, "spu-choice", -1 );
848
                }
849 850 851 852 853
                else
                {
                    /* subtitles were enabled: save the track id and disable */
                    i_new_id = -1;
                    var_SetInteger( p_input, "spu-choice", i_cur_id );
854 855
                }

856 857 858
                int i_new_index = 1; /* select first track by default */
                /* if subtitles were disabled with no saved id, use the first track */
                if( i_cur_id != -1 || i_new_id != -1 )
859
                {
860
                    for( int i = 0; i < list.i_count; ++i )
861
                    {
862
                        if( i_new_id == list.p_values[i].i_int )
863 864 865 866
                        {
                            i_new_index = i;
                            break;
                        }
867 868
                    }
                }
869
                var_SetInteger( p_input, "spu-es", list.p_values[i_new_index].i_int );
870
                DisplayMessage( p_vout, _("Subtitle track: %s"),
871
                                list2.p_values[i_new_index].psz_string );
872 873
                var_FreeList( &list, &list2 );
            }
874
            break;
875 876
        case ACTIONID_PROGRAM_SID_NEXT:
        case ACTIONID_PROGRAM_SID_PREV:
877
            if( p_input )
878
            {
879 880 881
                vlc_value_t val;
                vlc_list_t list, list2;
                int i;
882 883 884 885
                var_Get( p_input, "program", &val );

                var_Change( p_input, "program", VLC_VAR_GETCHOICES,
                            &list, &list2 );
886 887

                if( list.i_count <= 1 )
888
                {
889 890
                    DisplayMessage( p_vout, _("Program Service ID: %s"),
                                    _("N/A") );
891
                    var_FreeList( &list, &list2 );
892
                    break;
893
                }
894
                for( i = 0; i < list.i_count; i++ )
895
                {
896
                    if( val.i_int == list.p_values[i].i_int )
897 898 899 900
                    {
                        break;
                    }
                }
901
                /* value of program sid was not in choices list */
902
                if( i == list.i_count )
903 904 905 906 907
                {
                    msg_Warn( p_input,
                              "invalid current program SID, selecting 0" );
                    i = 0;
                }
908
                else if( i_action == ACTIONID_PROGRAM_SID_NEXT ) {
909
                    if( i == list.i_count - 1 )
910 911 912 913 914 915
                        i = 0;
                    else
                        i++;
                    }
                else { /* ACTIONID_PROGRAM_SID_PREV */
                    if( i == 0 )
916
                        i = list.i_count - 1;
917 918 919
                    else
                        i--;
                    }
920
                var_Set( p_input, "program", list.p_values[i] );
921
                DisplayMessage( p_vout, _("Program Service ID: %s"),
922
                                list2.p_values[i].psz_string );
923 924
                var_FreeList( &list, &list2 );
            }
925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
            break;

        case ACTIONID_JUMP_BACKWARD_EXTRASHORT:
        case ACTIONID_JUMP_FORWARD_EXTRASHORT:
        case ACTIONID_JUMP_BACKWARD_SHORT:
        case ACTIONID_JUMP_FORWARD_SHORT:
        case ACTIONID_JUMP_BACKWARD_MEDIUM:
        case ACTIONID_JUMP_FORWARD_MEDIUM:
        case ACTIONID_JUMP_BACKWARD_LONG:
        case ACTIONID_JUMP_FORWARD_LONG:
        {
            if( p_input == NULL || !var_GetBool( p_input, "can-seek" ) )
                break;

            const char *varname;
            int sign = +1;
            switch( i_action )
            {
                case ACTIONID_JUMP_BACKWARD_EXTRASHORT:
                    sign = -1;
945
                    /* fall through */
946 947 948 949 950
                case ACTIONID_JUMP_FORWARD_EXTRASHORT:
                    varname = "extrashort-jump-size";
                    break;
                case ACTIONID_JUMP_BACKWARD_SHORT:
                    sign = -1;
951
                    /* fall through */
952 953 954 955 956
                case ACTIONID_JUMP_FORWARD_SHORT:
                    varname = "short-jump-size";
                    break;
                case ACTIONID_JUMP_BACKWARD_MEDIUM:
                    sign = -1;
957
                    /* fall through */
958 959 960 961 962
                case ACTIONID_JUMP_FORWARD_MEDIUM:
                    varname = "medium-jump-size";
                    break;
                case ACTIONID_JUMP_BACKWARD_LONG:
                    sign = -1;
963
                    /* fall through */
964 965 966 967 968 969 970 971
                case ACTIONID_JUMP_FORWARD_LONG:
                    varname = "long-jump-size";
                    break;
            }

            mtime_t it = var_InheritInteger( p_input, varname );
            if( it < 0 )
                break;
972
            var_SetInteger( p_input, "time-offset", it * sign * CLOCK_FREQ );
973
            DisplayPosition( p_vout, slider_chan, p_input );
974 975 976
            break;
        }

977
        /* Input navigation */
978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997
        case ACTIONID_TITLE_PREV:
            if( p_input )
                var_TriggerCallback( p_input, "prev-title" );
            break;
        case ACTIONID_TITLE_NEXT:
            if( p_input )
                var_TriggerCallback( p_input, "next-title" );
            break;
        case ACTIONID_CHAPTER_PREV:
            if( p_input )
                var_TriggerCallback( p_input, "prev-chapter" );
            break;
        case ACTIONID_CHAPTER_NEXT:
            if( p_input )
                var_TriggerCallback( p_input, "next-chapter" );
            break;
        case ACTIONID_DISC_MENU:
            if( p_input )
                var_SetInteger( p_input, "title  0", 2 );
            break;
998
        case ACTIONID_NAV_ACTIVATE:
999 1000 1001
            if( p_input )
                input_Control( p_input, INPUT_NAV_ACTIVATE, NULL );
            break;
1002
        case ACTIONID_NAV_UP:
1003 1004 1005
            if( p_input )
                input_Control( p_input, INPUT_NAV_UP, NULL );
            break;
1006
        case ACTIONID_NAV_DOWN:
1007 1008 1009
            if( p_input )
                input_Control( p_input, INPUT_NAV_DOWN, NULL );
            break;
1010
        case ACTIONID_NAV_LEFT:
1011 1012 1013
            if( p_input )
                input_Control( p_input, INPUT_NAV_LEFT, NULL );
            break;
1014 1015
        case ACTIONID_NAV_RIGHT:
            if( p_input )
1016
                input_Control( p_input, INPUT_NAV_RIGHT, NULL );
1017
            break;
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027

        /* Video Output actions */
        case ACTIONID_SNAPSHOT:
            if( p_vout )
                var_TriggerCallback( p_vout, "video-snapshot" );
            break;

        case ACTIONID_TOGGLE_FULLSCREEN:
        {
            if( p_vout )
1028 1029 1030 1031 1032 1033
            {
                bool fs = var_ToggleBool( p_vout, "fullscreen" );
                var_SetBool( p_playlist, "fullscreen", fs );
            }
            else
                var_ToggleBool( p_playlist, "fullscreen" );
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
            break;
        }

        case ACTIONID_LEAVE_FULLSCREEN:
            if( p_vout )
                var_SetBool( p_vout, "fullscreen", false );
            var_SetBool( p_playlist, "fullscreen", false );
            break;

        case ACTIONID_ASPECT_RATIO:
            if( p_vout )
1045
            {
1046 1047 1048
                vlc_value_t val;
                vlc_list_t val_list, text_list;

1049
                var_Get( p_vout, "aspect-ratio", &val );
1050
                if( var_Change( p_vout, "aspect-ratio", VLC_VAR_GETCHOICES,
1051 1052 1053
                                &val_list, &text_list ) >= 0 )
                {
                    int i;
1054
                    for( i = 0; i < val_list.i_count; i++ )
1055
                    {
1056
                        if( !strcmp( val_list.p_values[i].psz_string,
1057 1058 1059 1060 1061 1062
                                     val.psz_string ) )
                        {
                            i++;
                            break;
                        }
                    }
1063
                    if( i == val_list.i_count ) i = 0;
1064
                    var_SetString( p_vout, "aspect-ratio",
1065
                                   val_list.p_values[i].psz_string );
1066
                    DisplayMessage( p_vout, _("Aspect ratio: %s"),
1067
                                    text_list.p_values[i].psz_string );
1068

1069
                    var_FreeList( &val_list, &text_list );
1070 1071 1072
                }
                free( val.psz_string );
            }
1073 1074 1075 1076
            break;

        case ACTIONID_CROP:
            if( p_vout )
1077
            {
1078 1079 1080
                vlc_value_t val;
                vlc_list_t val_list, text_list;

1081
                var_Get( p_vout, "crop", &val );
1082
                if( var_Change( p_vout, "crop", VLC_VAR_GETCHOICES,
1083 1084 1085
                                &val_list, &text_list ) >= 0 )
                {
                    int i;
1086
                    for( i = 0; i < val_list.i_count; i++ )
1087
                    {
1088
                        if( !strcmp( val_list.p_values[i].psz_string,
1089 1090 1091 1092 1093 1094
                                     val.psz_string ) )
                        {
                            i++;
                            break;
                        }
                    }
1095
                    if( i == val_list.i_count ) i = 0;
1096
                    var_SetString( p_vout, "crop",
1097
                                   val_list.p_values[i].psz_string );
1098
                    DisplayMessage( p_vout, _("Crop: %s"),
1099
                                    text_list.p_values[i].psz_string );
1100

1101
                    var_FreeList( &val_list, &text_list );
1102 1103 1104
                }
                free( val.psz_string );
            }
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
            break;
        case ACTIONID_CROP_TOP:
            if( p_vout )
                var_IncInteger( p_vout, "crop-top" );
            break;
        case ACTIONID_UNCROP_TOP:
            if( p_vout )
                var_DecInteger( p_vout, "crop-top" );
            break;
        case ACTIONID_CROP_BOTTOM:
            if( p_vout )
                var_IncInteger( p_vout, "crop-bottom" );
            break;
        case ACTIONID_UNCROP_BOTTOM:
            if( p_vout )
                var_DecInteger( p_vout, "crop-bottom" );
            break;
        case ACTIONID_CROP_LEFT:
            if( p_vout )
                var_IncInteger( p_vout, "crop-left" );
            break;
        case ACTIONID_UNCROP_LEFT:
            if( p_vout )
                var_DecInteger( p_vout, "crop-left" );
            break;
        case ACTIONID_CROP_RIGHT:
            if( p_vout )
                var_IncInteger( p_vout, "crop-right" );
            break;
        case ACTIONID_UNCROP_RIGHT:
            if( p_vout )
                var_DecInteger( p_vout, "crop-right" );
            break;

1139
        case ACTIONID_VIEWPOINT_FOV_IN:
1140 1141 1142 1143 1144
            if( p_vout )
                input_UpdateViewpoint( p_input,
                                       &(vlc_viewpoint_t) { .fov = -1.f },
                                       false );
            break;
1145
        case ACTIONID_VIEWPOINT_FOV_OUT:
1146 1147 1148 1149 1150 1151
            if( p_vout )
                input_UpdateViewpoint( p_input,
                                       &(vlc_viewpoint_t) { .fov = 1.f },
                                       false );
            break;

1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
        case ACTIONID_VIEWPOINT_ROLL_CLOCK:
            if( p_vout )
                input_UpdateViewpoint( p_input,
                                       &(vlc_viewpoint_t) { .roll = -1.f },
                                       false );
            break;
        case ACTIONID_VIEWPOINT_ROLL_ANTICLOCK:
            if( p_vout )
                input_UpdateViewpoint( p_input,
                                       &(vlc_viewpoint_t) { .roll = 1.f },
                                       false );
            break;

1165 1166
         case ACTIONID_TOGGLE_AUTOSCALE:
            if( p_vout )
1167
            {
1168
                float f_scalefactor = var_GetFloat( p_vout, "zoom" );
1169
                if ( f_scalefactor != 1.f )
1170
                {
1171
                    var_SetFloat( p_vout, "zoom", 1.f );
1172
                    DisplayMessage( p_vout, _("Zooming reset") );
1173 1174 1175 1176 1177
                }
                else
                {
                    bool b_autoscale = !var_GetBool( p_vout, "autoscale" );
                    var_SetBool( p_vout, "autoscale", b_autoscale );
1178
                    if( b_autoscale )
1179
                        DisplayMessage( p_vout, _("Scaled to screen") );
1180
                    else
1181
                        DisplayMessage( p_vout, _("Original Size") );
1182 1183
                }
            }
1184 1185 1186
            break;
        case ACTIONID_SCALE_UP:
            if( p_vout )
1187
            {
1188
               float f_scalefactor = var_GetFloat( p_vout, "zoom" );
1189

1190 1191
               if( f_scalefactor < 10.f )
                   f_scalefactor += .1f;
1192
               var_SetFloat( p_vout, "zoom", f_scalefactor );
1193
            }
1194 1195 1196
            break;
        case ACTIONID_SCALE_DOWN:
            if( p_vout )
1197
            {
1198
               float f_scalefactor = var_GetFloat( p_vout, "zoom" );
1199

1200 1201
               if( f_scalefactor > .3f )
                   f_scalefactor -= .1f;
1202
               var_SetFloat( p_vout, "zoom", f_scalefactor );
1203
            }
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227
            break;

        case ACTIONID_ZOOM_QUARTER:
        case ACTIONID_ZOOM_HALF:
        case ACTIONID_ZOOM_ORIGINAL:
        case ACTIONID_ZOOM_DOUBLE:
            if( p_vout )
            {
                float f;
                switch( i_action )
                {
                    case ACTIONID_ZOOM_QUARTER:  f = 0.25; break;
                    case ACTIONID_ZOOM_HALF:     f = 0.5;  break;
                    case ACTIONID_ZOOM_ORIGINAL: f = 1.;   break;
                     /*case ACTIONID_ZOOM_DOUBLE:*/
                    default:                     f = 2.;   break;
                }
                var_SetFloat( p_vout, "zoom", f );
            }
            break;
        case ACTIONID_ZOOM:
        case ACTIONID_UNZOOM:
            if( p_vout )
            {
1228 1229 1230
                vlc_value_t val;
                vlc_list_t val_list, text_list;

1231
                var_Get( p_vout, "zoom", &val );
1232
                if( var_Change( p_vout, "zoom", VLC_VAR_GETCHOICES,
Rémi Denis-Courmont's avatar