]> git.sesse.net Git - vlc/blob - src/osd/osd.c
Cleanup indentation.
[vlc] / src / osd / osd.c
1 /*****************************************************************************
2  * osd.c - The OSD Menu core code.
3  *****************************************************************************
4  * Copyright (C) 2005-2007 M2X
5  * $Id$
6  *
7  * Authors: Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #include <vlc/vlc.h>
29 #include <vlc_keys.h>
30 #include <vlc_osd.h>
31 #include "libvlc.h"
32 #include <vlc_image.h>
33
34 #undef OSD_MENU_DEBUG
35
36 /*****************************************************************************
37  * Local prototypes
38  *****************************************************************************/
39
40 static void osd_UpdateState( osd_menu_state_t *, int, int, int, int, picture_t * );
41 static inline osd_state_t *osd_VolumeStateChange( osd_state_t *, int );
42 static int osd_VolumeStep( vlc_object_t *, int, int );
43 static vlc_bool_t osd_isVisible( osd_menu_t *p_osd );
44 static int  osd_ParserLoad( vlc_object_t *, const char *, osd_menu_t ** );
45 static void osd_ParserUnload( vlc_object_t *, osd_menu_t ** );
46
47 static vlc_bool_t osd_isVisible( osd_menu_t *p_osd )
48 {
49     vlc_value_t val;
50
51     var_Get( p_osd, "osd-menu-visible", &val );
52     return val.b_bool;
53 }
54
55 /*****************************************************************************
56  * Wrappers for loading and unloading osd parser modules.
57  *****************************************************************************/
58 static int osd_ParserLoad( vlc_object_t *p_this, const char *psz_file,
59                            osd_menu_t **pp_menu )
60 {
61     osd_menu_t *p_menu = *pp_menu;
62
63     if( pp_menu && p_menu ) return VLC_EGENERIC;
64
65     p_menu = vlc_object_create( p_this, VLC_OBJECT_OSDMENU );
66     if( !p_menu )
67     {
68         msg_Err( p_this, "out of memory" );
69         return VLC_ENOMEM;
70     }
71     vlc_object_attach( p_this, p_menu );
72
73     /* Stuff needed for Parser */
74     p_menu->psz_file = strdup( psz_file );
75     p_menu->p_image = image_HandlerCreate( p_this );
76     if( !p_menu->p_image || !p_menu->psz_file )
77     {
78         msg_Err( p_this, "unable to load images, aborting .." );
79         osd_ParserUnload( p_this, pp_menu );
80         return VLC_ENOMEM;
81     }
82     else
83     {
84         char *psz_type;
85         char *psz_ext = strrchr( p_menu->psz_file, '.' );
86
87         if( psz_ext && !strcmp( psz_ext, ".cfg") )
88             psz_type = "import-osd";
89         else
90             psz_type = "import-osd-xml";
91
92         p_menu->p_parser = module_Need( p_menu, "osd parser",
93                                         psz_type, VLC_TRUE );
94         if( !p_menu->p_parser )
95         {
96             osd_ParserUnload( p_this, pp_menu );
97             return VLC_ENOOBJ;
98         }
99     }
100     return VLC_SUCCESS;
101 }
102
103 static void osd_ParserUnload( vlc_object_t *p_this, osd_menu_t **pp_menu )
104 {
105     osd_menu_t *p_menu = (osd_menu_t *) *pp_menu;
106
107     if( p_menu->p_parser )
108     {
109         module_Unneed( p_menu, p_menu->p_parser );
110     }
111     p_menu->p_parser = NULL;
112
113     if( p_menu->p_image )
114         image_HandlerDelete( p_menu->p_image );
115     if( p_menu->psz_file )
116         free( p_menu->psz_file );
117
118     vlc_object_detach( p_menu );
119     vlc_object_destroy( p_menu );
120     p_menu = NULL;
121 }
122
123 /*****************************************************************************
124  * OSD menu Funtions
125  *****************************************************************************/
126 osd_menu_t *__osd_MenuCreate( vlc_object_t *p_this, const char *psz_file )
127 {
128     osd_menu_t  *p_osd = NULL;
129     vlc_value_t lockval;
130     int         i_volume = 0;
131     int         i_steps = 0;
132
133     /* to be sure to avoid multiple creation */
134     var_Create( p_this->p_libvlc, "osd_mutex", VLC_VAR_MUTEX );
135     var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
136     vlc_mutex_lock( lockval.p_address );
137
138     p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
139     if( p_osd == NULL )
140     {
141         vlc_value_t val;
142
143         /* Parse configuration file */
144         if( osd_ParserLoad( p_this, psz_file, &p_osd ) )
145             goto error;
146
147         /* Setup default button (first button) */
148         p_osd->p_state->p_visible = p_osd->p_button;
149         p_osd->p_state->p_visible->p_current_state =
150             osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );
151         p_osd->i_width  = p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch;
152         p_osd->i_height = p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines;
153
154         if( p_osd->p_state->p_volume )
155         {
156             /* Update the volume state images to match the current volume */
157             i_volume = config_GetInt( p_this, "volume" );
158             i_steps = osd_VolumeStep( p_this, i_volume, p_osd->p_state->p_volume->i_ranges );
159             p_osd->p_state->p_volume->p_current_state = osd_VolumeStateChange(
160                                     p_osd->p_state->p_volume->p_states, i_steps );
161         }
162         /* Initialize OSD state */
163         osd_UpdateState( p_osd->p_state, p_osd->i_x, p_osd->i_y,
164                          p_osd->i_width, p_osd->i_height, NULL );
165
166         vlc_object_yield( p_osd );
167         vlc_object_attach( p_osd, p_this->p_libvlc );
168
169         /* Signal when an update of OSD menu is needed */
170         var_Create( p_osd, "osd-menu-update", VLC_VAR_BOOL );
171         var_Create( p_osd, "osd-menu-visible", VLC_VAR_BOOL );
172
173         val.b_bool = VLC_FALSE;
174         var_Set( p_osd, "osd-menu-update", val );
175         var_Set( p_osd, "osd-menu-visible", val );
176     }
177     vlc_mutex_unlock( lockval.p_address );
178     return p_osd;
179
180 error:
181     msg_Err( p_this, "creating OSD menu object failed" );
182
183     if( p_osd->p_image )
184         image_HandlerDelete( p_osd->p_image );
185     if( p_osd->psz_file )
186         free( p_osd->psz_file );
187
188     vlc_mutex_unlock( lockval.p_address );
189     vlc_object_destroy( p_osd );
190     vlc_mutex_unlock( lockval.p_address );
191     return NULL;
192 }
193
194 void __osd_MenuDelete( vlc_object_t *p_this, osd_menu_t *p_osd )
195 {
196     vlc_value_t lockval;
197
198     if( !p_osd || !p_this ) return;
199
200     var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
201     vlc_mutex_lock( lockval.p_address );
202
203     vlc_object_release( p_osd );
204     if( p_osd->p_internals->i_refcount > 0 )
205     {
206         vlc_mutex_unlock( lockval.p_address );
207         return;
208     }
209
210     var_Destroy( p_osd, "osd-menu-visible" );
211     var_Destroy( p_osd, "osd-menu-update" );
212
213     osd_ParserUnload( p_this, &p_osd );
214
215     vlc_mutex_unlock( lockval.p_address );
216 }
217
218 osd_state_t *__osd_StateChange( osd_state_t *p_states, const int i_state )
219 {
220     osd_state_t *p_current = p_states;
221     osd_state_t *p_temp = NULL;
222     int i = 0;
223
224     for( i=0; p_current != NULL; i++ )
225     {
226         if( p_current->i_state == i_state )
227             return p_current;
228         p_temp = p_current->p_next;
229         p_current = p_temp;
230     }
231     return p_states;
232 }
233
234 /* The volume can be modified in another interface while the OSD Menu
235  * has not been instantiated yet. This routines updates the "volume OSD menu item"
236  * to reflect the current state of the GUI.
237  */
238 static inline osd_state_t *osd_VolumeStateChange( osd_state_t *p_current, int i_steps )
239 {
240     osd_state_t *p_temp = NULL;
241     int i;
242
243     if( i_steps < 0 ) i_steps = 0;
244
245     for( i=0; (i < i_steps) && (p_current != NULL); i++ )
246     {
247         p_temp = p_current->p_next;
248         if( !p_temp ) return p_current;
249         p_current = p_temp;
250     }
251     return (!p_temp) ? p_current : p_temp;
252 }
253
254 /* Update the state of the OSD Menu */
255 static void osd_UpdateState( osd_menu_state_t *p_state, int i_x, int i_y,
256         int i_width, int i_height, picture_t *p_pic )
257 {
258     p_state->i_x = i_x;
259     p_state->i_y = i_y;
260     p_state->i_width = i_width;
261     p_state->i_height = i_height;
262     p_state->p_pic = p_pic;
263 }
264
265 void __osd_MenuShow( vlc_object_t *p_this )
266 {
267     osd_menu_t *p_osd = NULL;
268     osd_button_t *p_button = NULL;
269     vlc_value_t lockval;
270
271     p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
272     if( p_osd == NULL )
273     {
274         msg_Err( p_this, "osd_MenuNext failed" );
275         return;
276     }
277
278     var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
279     vlc_mutex_lock( lockval.p_address );
280
281 #if defined(OSD_MENU_DEBUG)
282     msg_Dbg( p_osd, "menu on" );
283 #endif
284     p_button = p_osd->p_state->p_visible;
285     if( p_button )
286     {
287         if( !p_button->b_range )
288             p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_UNSELECT );
289         p_osd->p_state->p_visible = p_osd->p_button;
290
291         if( !p_osd->p_state->p_visible->b_range )
292             p_osd->p_state->p_visible->p_current_state =
293                 osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );
294
295         osd_UpdateState( p_osd->p_state,
296                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
297                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
298                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
299                 p_osd->p_state->p_visible->p_current_state->p_pic );
300         osd_SetMenuUpdate( p_osd, VLC_TRUE );
301     }
302     osd_SetMenuVisible( p_osd, VLC_TRUE );
303
304     vlc_object_release( (vlc_object_t*) p_osd );
305     vlc_mutex_unlock( lockval.p_address );
306 }
307
308 void __osd_MenuHide( vlc_object_t *p_this )
309 {
310     osd_menu_t *p_osd = NULL;
311     vlc_value_t lockval;
312
313     p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
314     if( p_osd == NULL )
315     {
316         msg_Err( p_this, "osd_MenuNext failed" );
317         return;
318     }
319
320     var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
321     vlc_mutex_lock( lockval.p_address );
322
323 #if defined(OSD_MENU_DEBUG)
324     msg_Dbg( p_osd, "menu off" );
325 #endif
326     osd_UpdateState( p_osd->p_state,
327                 p_osd->p_state->i_x, p_osd->p_state->i_y,
328                 0, 0, NULL );
329     osd_SetMenuUpdate( p_osd, VLC_TRUE );
330
331     vlc_object_release( (vlc_object_t*) p_osd );
332     vlc_mutex_unlock( lockval.p_address );
333 }
334
335 void __osd_MenuActivate( vlc_object_t *p_this )
336 {
337     osd_menu_t *p_osd = NULL;
338     osd_button_t *p_button = NULL;
339     vlc_value_t lockval;
340
341     p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
342     if( p_osd == NULL )
343     {
344         msg_Err( p_this, "osd_MenuNext failed" );
345         return;
346     }
347
348     if( osd_isVisible( p_osd ) == VLC_FALSE )
349     {
350         vlc_object_release( (vlc_object_t*) p_osd );
351         return;
352     }
353
354     var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
355     vlc_mutex_lock( lockval.p_address );
356
357 #if defined(OSD_MENU_DEBUG)
358     msg_Dbg( p_osd, "select" );
359 #endif
360     p_button = p_osd->p_state->p_visible;
361     /*
362      * Is there a menu item above or below? If so, then select it.
363      */
364     if( p_button && p_button->p_up )
365     {
366         vlc_object_release( (vlc_object_t*) p_osd );
367         vlc_mutex_unlock( lockval.p_address );
368         __osd_MenuUp( p_this );   /* "menu select" means go to menu item above. */
369         return;
370     }
371     if( p_button && p_button->p_down )
372     {
373         vlc_object_release( (vlc_object_t*) p_osd );
374         vlc_mutex_unlock( lockval.p_address );
375         __osd_MenuDown( p_this ); /* "menu select" means go to menu item below. */
376         return;
377     }
378
379     if( p_button && !p_button->b_range )
380     {
381         p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_PRESSED );
382         osd_UpdateState( p_osd->p_state,
383                 p_button->i_x, p_button->i_y,
384                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
385                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
386                 p_button->p_current_state->p_pic );
387         osd_SetMenuUpdate( p_osd, VLC_TRUE );
388         osd_SetMenuVisible( p_osd, VLC_TRUE );
389         osd_SetKeyPressed( VLC_OBJECT(p_osd->p_libvlc), config_GetInt( p_osd, p_button->psz_action ) );
390 #if defined(OSD_MENU_DEBUG)
391         msg_Dbg( p_osd, "select (%d, %s)", config_GetInt( p_osd, p_button->psz_action ), p_button->psz_action );
392 #endif
393     }
394     vlc_object_release( (vlc_object_t*) p_osd );
395     vlc_mutex_unlock( lockval.p_address );
396 }
397
398 void __osd_MenuNext( vlc_object_t *p_this )
399 {
400     osd_menu_t *p_osd = NULL;
401     osd_button_t *p_button = NULL;
402     vlc_value_t lockval;
403
404     p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
405     if( p_osd == NULL )
406     {
407         msg_Err( p_this, "osd_MenuNext failed" );
408         return;
409     }
410
411     if( osd_isVisible( p_osd ) == VLC_FALSE )
412     {
413         vlc_object_release( (vlc_object_t*) p_osd );
414         return;
415     }
416
417     var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
418     vlc_mutex_lock( lockval.p_address );
419
420     p_button = p_osd->p_state->p_visible;
421     if( p_button )
422     {
423         if( !p_button->b_range )
424             p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_UNSELECT );
425         if( p_button->p_next )
426             p_osd->p_state->p_visible = p_button->p_next;
427         else
428             p_osd->p_state->p_visible = p_osd->p_button;
429
430         if( !p_osd->p_state->p_visible->b_range )
431             p_osd->p_state->p_visible->p_current_state =
432                 osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );
433
434         osd_UpdateState( p_osd->p_state,
435                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
436                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
437                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
438                 p_osd->p_state->p_visible->p_current_state->p_pic );
439         osd_SetMenuUpdate( p_osd, VLC_TRUE );
440     }
441 #if defined(OSD_MENU_DEBUG)
442     msg_Dbg( p_osd, "direction right [button %s]", p_osd->p_state->p_visible->psz_action );
443 #endif
444
445     vlc_object_release( (vlc_object_t*) p_osd );
446     vlc_mutex_unlock( lockval.p_address );
447 }
448
449 void __osd_MenuPrev( vlc_object_t *p_this )
450 {
451     osd_menu_t *p_osd = NULL;
452     osd_button_t *p_button = NULL;
453     vlc_value_t lockval;
454
455     p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
456     if( p_osd == NULL )
457     {
458         msg_Err( p_this, "osd_MenuPrev failed" );
459         return;
460     }
461
462     if( osd_isVisible( p_osd ) == VLC_FALSE )
463     {
464         vlc_object_release( (vlc_object_t*) p_osd );
465         return;
466     }
467
468     var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
469     vlc_mutex_lock( lockval.p_address );
470
471     p_button = p_osd->p_state->p_visible;
472     if( p_button )
473     {
474         if( !p_button->b_range )
475             p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_UNSELECT );
476         if( p_button->p_prev )
477             p_osd->p_state->p_visible = p_button->p_prev;
478         else
479             p_osd->p_state->p_visible = p_osd->p_last_button;
480
481         if( !p_osd->p_state->p_visible->b_range )
482             p_osd->p_state->p_visible->p_current_state =
483                 osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );
484
485         osd_UpdateState( p_osd->p_state,
486                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
487                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
488                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
489                 p_osd->p_state->p_visible->p_current_state->p_pic );
490         osd_SetMenuUpdate( p_osd, VLC_TRUE );
491     }
492 #if defined(OSD_MENU_DEBUG)
493     msg_Dbg( p_osd, "direction left [button %s]", p_osd->p_state->p_visible->psz_action );
494 #endif
495
496     vlc_object_release( (vlc_object_t*) p_osd );
497     vlc_mutex_unlock( lockval.p_address );
498 }
499
500 void __osd_MenuUp( vlc_object_t *p_this )
501 {
502     osd_menu_t *p_osd = NULL;
503     osd_button_t *p_button = NULL;
504     vlc_value_t lockval;
505 #if defined(OSD_MENU_DEBUG)
506     vlc_value_t val;
507 #endif
508     p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
509     if( p_osd == NULL )
510     {
511         msg_Err( p_this, "osd_MenuDown failed" );
512         return;
513     }
514
515     if( osd_isVisible( p_osd ) == VLC_FALSE )
516     {
517         vlc_object_release( (vlc_object_t*) p_osd );
518         return;
519     }
520
521     var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
522     vlc_mutex_lock( lockval.p_address );
523
524     p_button = p_osd->p_state->p_visible;
525     if( p_button )
526     {
527         if( !p_button->b_range )
528         {
529             p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_SELECT );
530             if( p_button->p_up )
531                 p_osd->p_state->p_visible = p_button->p_up;
532         }
533
534         if( p_button->b_range && p_osd->p_state->p_visible->b_range )
535         {
536             osd_state_t *p_temp = p_osd->p_state->p_visible->p_current_state;
537             if( p_temp && p_temp->p_next )
538                 p_osd->p_state->p_visible->p_current_state = p_temp->p_next;
539         }
540         else if( !p_osd->p_state->p_visible->b_range )
541         {
542             p_osd->p_state->p_visible->p_current_state =
543                 osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );
544         }
545
546         osd_UpdateState( p_osd->p_state,
547                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
548                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
549                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
550                 p_osd->p_state->p_visible->p_current_state->p_pic );
551         osd_SetMenuUpdate( p_osd, VLC_TRUE );
552         /* If this is a range style action with associated images of only one state,
553             * then perform "menu select" on every menu navigation
554             */
555         if( p_button->b_range )
556         {
557             osd_SetKeyPressed( VLC_OBJECT(p_osd->p_libvlc), config_GetInt(p_osd, p_button->psz_action) );
558 #if defined(OSD_MENU_DEBUG)
559             msg_Dbg( p_osd, "select (%d, %s)", val.i_int, p_button->psz_action );
560 #endif
561         }
562     }
563 #if defined(OSD_MENU_DEBUG)
564     msg_Dbg( p_osd, "direction up [button %s]", p_osd->p_state->p_visible->psz_action );
565 #endif
566
567     vlc_object_release( (vlc_object_t*) p_osd );
568     vlc_mutex_unlock( lockval.p_address );
569 }
570
571 void __osd_MenuDown( vlc_object_t *p_this )
572 {
573     osd_menu_t *p_osd = NULL;
574     osd_button_t *p_button = NULL;
575     vlc_value_t lockval;
576 #if defined(OSD_MENU_DEBUG)
577     vlc_value_t val;
578 #endif
579
580     p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
581     if( p_osd == NULL )
582     {
583         msg_Err( p_this, "osd_MenuDown failed" );
584         return;
585     }
586
587     if( osd_isVisible( p_osd ) == VLC_FALSE )
588     {
589         vlc_object_release( (vlc_object_t*) p_osd );
590         return;
591     }
592
593     var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
594     vlc_mutex_lock( lockval.p_address );
595
596     p_button = p_osd->p_state->p_visible;
597     if( p_button )
598     {
599         if( !p_button->b_range )
600         {
601             p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_SELECT );
602             if( p_button->p_down )
603                 p_osd->p_state->p_visible = p_button->p_down;
604         }
605
606         if( p_button->b_range && p_osd->p_state->p_visible->b_range )
607         {
608             osd_state_t *p_temp = p_osd->p_state->p_visible->p_current_state;
609             if( p_temp && p_temp->p_prev )
610                 p_osd->p_state->p_visible->p_current_state = p_temp->p_prev;
611         }
612         else if( !p_osd->p_state->p_visible->b_range )
613         {
614             p_osd->p_state->p_visible->p_current_state =
615                 osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );
616         }
617
618         osd_UpdateState( p_osd->p_state,
619                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
620                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
621                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
622                 p_osd->p_state->p_visible->p_current_state->p_pic );
623         osd_SetMenuUpdate( p_osd, VLC_TRUE );
624         /* If this is a range style action with associated images of only one state,
625          * then perform "menu select" on every menu navigation
626          */
627         if( p_button->b_range )
628         {
629             osd_SetKeyPressed( VLC_OBJECT(p_osd->p_libvlc), config_GetInt(p_osd, p_button->psz_action_down) );
630 #if defined(OSD_MENU_DEBUG)
631             msg_Dbg( p_osd, "select (%d, %s)", val.i_int, p_button->psz_action_down );
632 #endif
633         }
634     }
635 #if defined(OSD_MENU_DEBUG)
636     msg_Dbg( p_osd, "direction down [button %s]", p_osd->p_state->p_visible->psz_action );
637 #endif
638
639     vlc_object_release( (vlc_object_t*) p_osd );
640     vlc_mutex_unlock( lockval.p_address );
641 }
642
643 static int osd_VolumeStep( vlc_object_t *p_this, int i_volume, int i_steps )
644 {
645     int i_volume_step = 0;
646     (void)i_steps;
647
648     i_volume_step = config_GetInt( p_this->p_libvlc, "volume-step" );
649     return (i_volume/i_volume_step);
650 }
651
652 /**
653  * Display current audio volume bitmap
654  *
655  * The OSD Menu audio volume bar is updated to reflect the new audio volume. Call this function
656  * when the audio volume is updated outside the OSD menu command "menu up", "menu down" or "menu select".
657  */
658 void __osd_Volume( vlc_object_t *p_this )
659 {
660     osd_menu_t *p_osd = NULL;
661     osd_button_t *p_button = NULL;
662     vlc_value_t lockval;
663     int i_volume = 0;
664     int i_steps = 0;
665
666     p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
667     if( p_osd == NULL )
668     {
669         msg_Err( p_this, "OSD menu volume update failed" );
670         return;
671     }
672
673     if( p_osd->p_state && p_osd->p_state->p_volume )
674     {
675         var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
676         vlc_mutex_lock( lockval.p_address );
677
678         p_button = p_osd->p_state->p_volume;
679         if( p_osd->p_state->p_volume )
680             p_osd->p_state->p_visible = p_osd->p_state->p_volume;
681         if( p_button && p_button->b_range )
682         {
683             /* Update the volume state images to match the current volume */
684             i_volume = config_GetInt( p_this, "volume" );
685             i_steps = osd_VolumeStep( p_this, i_volume, p_button->i_ranges );
686             p_button->p_current_state = osd_VolumeStateChange( p_button->p_states, i_steps );
687
688             osd_UpdateState( p_osd->p_state,
689                     p_button->i_x, p_button->i_y,
690                     p_button->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
691                     p_button->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
692                     p_button->p_current_state->p_pic );
693             osd_SetMenuUpdate( p_osd, VLC_TRUE );
694             osd_SetMenuVisible( p_osd, VLC_TRUE );
695         }
696         vlc_object_release( (vlc_object_t*) p_osd );
697         vlc_mutex_unlock( lockval.p_address );
698     }
699 }