]> git.sesse.net Git - vlc/blob - src/osd/osd.c
For consistency, remove references to vlc from libvlc
[vlc] / src / osd / osd.c
1 /*****************************************************************************
2  * osd.c - The OSD Menu core code.
3  *****************************************************************************
4  * Copyright (C) 2005 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 #include <stdlib.h>
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc_keys.h>
32 #include <vlc_osd.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
45 static vlc_bool_t osd_isVisible( osd_menu_t *p_osd )
46 {
47     vlc_value_t val;
48
49     var_Get( p_osd, "osd-menu-visible", &val );
50     return val.b_bool;
51 }
52
53 /*****************************************************************************
54  * OSD menu Funtions
55  *****************************************************************************/
56 osd_menu_t *__osd_MenuCreate( vlc_object_t *p_this, const char *psz_file )
57 {
58     osd_menu_t  *p_osd = NULL;
59     vlc_value_t lockval;
60     int         i_volume = 0;
61     int         i_steps = 0;
62
63     /* to be sure to avoid multiple creation */
64     var_Create( p_this->p_libvlc_global, "osd_mutex", VLC_VAR_MUTEX );
65     var_Get( p_this->p_libvlc_global, "osd_mutex", &lockval );
66     vlc_mutex_lock( lockval.p_address );
67
68     if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )
69     {
70         vlc_value_t val;
71
72         msg_Dbg( p_this, "creating OSD menu object" );
73         if( ( p_osd = vlc_object_create( p_this, VLC_OBJECT_OSDMENU ) ) == NULL )
74         {
75             msg_Err( p_this, "out of memory" );
76             vlc_mutex_unlock( lockval.p_address );
77             return NULL;
78         }
79
80         /* Parse configuration file */
81         if( osd_ConfigLoader( p_this, psz_file, &p_osd ) )
82             goto error;
83
84         /* Setup default button (first button) */
85         p_osd->p_state->p_visible = p_osd->p_button;
86         p_osd->p_state->p_visible->p_current_state =
87             osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );
88         p_osd->i_width  = p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch;
89         p_osd->i_height = p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines;
90
91         /* Update the volume state images to match the current volume */
92         i_volume = config_GetInt( p_this, "volume" );
93         i_steps = osd_VolumeStep( p_this, i_volume, p_osd->p_state->p_volume->i_ranges );
94         p_osd->p_state->p_volume->p_current_state = osd_VolumeStateChange( p_osd->p_state->p_volume->p_states, i_steps );
95
96         /* Initialize OSD state */
97         osd_UpdateState( p_osd->p_state, p_osd->i_x, p_osd->i_y,
98                          p_osd->i_width, p_osd->i_height, NULL );
99
100         vlc_object_yield( p_osd );
101         vlc_object_attach( p_osd, p_this->p_libvlc );
102
103         /* Signal when an update of OSD menu is needed */
104         var_Create( p_osd, "osd-menu-update", VLC_VAR_BOOL );
105         var_Create( p_osd, "osd-menu-visible", VLC_VAR_BOOL );
106
107         val.b_bool = VLC_FALSE;
108         var_Set( p_osd, "osd-menu-update", val );
109         var_Set( p_osd, "osd-menu-visible", val );
110     }
111     vlc_mutex_unlock( lockval.p_address );
112     return p_osd;
113
114 error:
115     msg_Err( p_this, "creating OSD menu object failed" );
116     vlc_mutex_unlock( lockval.p_address );
117     vlc_object_destroy( p_osd );
118     return NULL;
119 }
120
121 void __osd_MenuDelete( vlc_object_t *p_this, osd_menu_t *p_osd )
122 {
123     vlc_value_t lockval;
124
125     if( !p_osd || !p_this ) return;
126
127     var_Get( p_this->p_libvlc_global, "osd_mutex", &lockval );
128     vlc_mutex_lock( lockval.p_address );
129
130     vlc_object_release( p_osd );
131     if( p_osd->i_refcount > 0 )
132     {
133         vlc_mutex_unlock( lockval.p_address );
134         return;
135     }
136
137     var_Destroy( p_osd, "osd-menu-visible" );
138     var_Destroy( p_osd, "osd-menu-update" );
139
140     osd_ConfigUnload( p_this, &p_osd );
141     vlc_object_detach( p_osd );
142     vlc_object_destroy( p_osd );
143     p_osd = NULL;
144
145     vlc_mutex_unlock( lockval.p_address );
146 }
147
148 osd_state_t *__osd_StateChange( osd_state_t *p_states, const int i_state )
149 {
150     osd_state_t *p_current = p_states;
151     osd_state_t *p_temp = NULL;
152     int i = 0;
153
154     for( i=0; p_current != NULL; i++ )
155     {
156         if( p_current->i_state == i_state )
157             return p_current;
158         p_temp = p_current->p_next;
159         p_current = p_temp;
160     }
161     return p_states;
162 }
163
164 /* The volume can be modified in another interface while the OSD Menu 
165  * has not been instantiated yet. This routines updates the "volume OSD menu item"
166  * to reflect the current state of the GUI.
167  */
168 static inline osd_state_t *osd_VolumeStateChange( osd_state_t *p_current, int i_steps )
169 {
170     osd_state_t *p_temp = NULL;
171     int i;
172
173     if( i_steps < 0 ) i_steps = 0;
174
175     for( i=0; (i < i_steps) && (p_current != NULL); i++ )
176     {
177         p_temp = p_current->p_next;
178         if( !p_temp ) return p_current;
179         p_current = p_temp;
180     }
181     return (!p_temp) ? p_current : p_temp;
182 }
183
184 /* Update the state of the OSD Menu */
185 static void osd_UpdateState( osd_menu_state_t *p_state, int i_x, int i_y,
186         int i_width, int i_height, picture_t *p_pic )
187 {
188     p_state->i_x = i_x;
189     p_state->i_y = i_y;
190     p_state->i_width = i_width;
191     p_state->i_height = i_height;
192     p_state->p_pic = p_pic;
193 }
194
195 void __osd_MenuShow( vlc_object_t *p_this )
196 {
197     osd_menu_t *p_osd = NULL;
198     osd_button_t *p_button = NULL;
199     vlc_value_t lockval;
200
201     if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )
202     {
203         msg_Err( p_this, "osd_MenuNext failed" );
204         return;
205     }
206
207     var_Get( p_this->p_libvlc_global, "osd_mutex", &lockval );
208     vlc_mutex_lock( lockval.p_address );
209
210 #if defined(OSD_MENU_DEBUG)
211     msg_Dbg( p_osd, "menu on" );
212 #endif
213     p_button = p_osd->p_state->p_visible;
214     if( p_button )
215     {
216         if( !p_button->b_range ) 
217             p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_UNSELECT );
218         p_osd->p_state->p_visible = p_osd->p_button;
219
220         if( !p_osd->p_state->p_visible->b_range ) 
221             p_osd->p_state->p_visible->p_current_state =
222                 osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );
223
224         osd_UpdateState( p_osd->p_state,
225                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
226                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
227                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
228                 p_osd->p_state->p_visible->p_current_state->p_pic );
229         osd_SetMenuUpdate( p_osd, VLC_TRUE );
230     }
231     osd_SetMenuVisible( p_osd, VLC_TRUE );
232
233     vlc_object_release( (vlc_object_t*) p_osd );
234     vlc_mutex_unlock( lockval.p_address );
235 }
236
237 void __osd_MenuHide( vlc_object_t *p_this )
238 {
239     osd_menu_t *p_osd = NULL;
240     vlc_value_t lockval;
241
242     if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )
243     {
244         msg_Err( p_this, "osd_MenuNext failed" );
245         return;
246     }
247
248     var_Get( p_this->p_libvlc_global, "osd_mutex", &lockval );
249     vlc_mutex_lock( lockval.p_address );
250
251 #if defined(OSD_MENU_DEBUG)
252     msg_Dbg( p_osd, "menu off" );
253 #endif
254     osd_UpdateState( p_osd->p_state,
255                 p_osd->p_state->i_x, p_osd->p_state->i_y,
256                 0, 0, NULL );
257     osd_SetMenuUpdate( p_osd, VLC_TRUE );
258
259     vlc_object_release( (vlc_object_t*) p_osd );
260     vlc_mutex_unlock( lockval.p_address );
261 }
262
263 void __osd_MenuActivate( vlc_object_t *p_this )
264 {
265     osd_menu_t *p_osd = NULL;
266     osd_button_t *p_button = NULL;
267     vlc_value_t lockval;
268
269     if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )
270     {
271         msg_Err( p_this, "osd_MenuNext failed" );
272         return;
273     }
274
275     if( osd_isVisible( p_osd ) == VLC_FALSE )
276     {
277         vlc_object_release( (vlc_object_t*) p_osd );
278         return;
279     }
280
281     var_Get( p_this->p_libvlc_global, "osd_mutex", &lockval );
282     vlc_mutex_lock( lockval.p_address );
283
284 #if defined(OSD_MENU_DEBUG)
285     msg_Dbg( p_osd, "select" );
286 #endif
287     p_button = p_osd->p_state->p_visible;
288     /*
289      * Is there a menu item above or below? If so, then select it.
290      */
291     if( p_button && p_button->p_up)
292     {
293         vlc_object_release( (vlc_object_t*) p_osd );
294         vlc_mutex_unlock( lockval.p_address );
295         __osd_MenuUp( p_this );   /* "menu select" means go to menu item above. */
296         return;
297     }
298     if( p_button && p_button->p_down)
299     {
300         vlc_object_release( (vlc_object_t*) p_osd );
301         vlc_mutex_unlock( lockval.p_address );
302         __osd_MenuDown( p_this ); /* "menu select" means go to menu item below. */
303         return;
304     }
305
306     if( p_button && !p_button->b_range )
307     {
308         p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_PRESSED );
309         osd_UpdateState( p_osd->p_state,
310                 p_button->i_x, p_button->i_y,
311                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
312                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
313                 p_button->p_current_state->p_pic );
314         osd_SetMenuUpdate( p_osd, VLC_TRUE );
315         osd_SetMenuVisible( p_osd, VLC_TRUE );
316         osd_SetKeyPressed( VLC_OBJECT(p_osd->p_libvlc), config_GetInt( p_osd, p_button->psz_action ) );
317 #if defined(OSD_MENU_DEBUG)
318         msg_Dbg( p_osd, "select (%d, %s)", config_GetInt( p_osd, p_button->psz_action ), p_button->psz_action );
319 #endif
320     }
321     vlc_object_release( (vlc_object_t*) p_osd );
322     vlc_mutex_unlock( lockval.p_address );
323 }
324
325 void __osd_MenuNext( vlc_object_t *p_this )
326 {
327     osd_menu_t *p_osd = NULL;
328     osd_button_t *p_button = NULL;
329     vlc_value_t lockval;
330
331     if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )
332     {
333         msg_Err( p_this, "osd_MenuNext failed" );
334         return;
335     }
336
337     if( osd_isVisible( p_osd ) == VLC_FALSE )
338     {
339         vlc_object_release( (vlc_object_t*) p_osd );
340         return;
341     }
342
343     var_Get( p_this->p_libvlc_global, "osd_mutex", &lockval );
344     vlc_mutex_lock( lockval.p_address );
345
346     p_button = p_osd->p_state->p_visible;
347     if( p_button )
348     {
349         if( !p_button->b_range ) 
350             p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_UNSELECT );
351         if( p_button->p_next )
352             p_osd->p_state->p_visible = p_button->p_next;
353         else
354             p_osd->p_state->p_visible = p_osd->p_button;
355
356         if( !p_osd->p_state->p_visible->b_range ) 
357             p_osd->p_state->p_visible->p_current_state =
358                 osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );
359
360         osd_UpdateState( p_osd->p_state, 
361                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
362                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
363                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
364                 p_osd->p_state->p_visible->p_current_state->p_pic );
365         osd_SetMenuUpdate( p_osd, VLC_TRUE );
366     }
367 #if defined(OSD_MENU_DEBUG)
368     msg_Dbg( p_osd, "direction right [button %s]", p_osd->p_state->p_visible->psz_action );
369 #endif
370
371     vlc_object_release( (vlc_object_t*) p_osd );
372     vlc_mutex_unlock( lockval.p_address );
373 }
374
375 void __osd_MenuPrev( vlc_object_t *p_this )
376 {
377     osd_menu_t *p_osd = NULL;
378     osd_button_t *p_button = NULL;
379     vlc_value_t lockval;
380
381     if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )
382     {
383         msg_Err( p_this, "osd_MenuPrev failed" );
384         return;
385     }
386
387     if( osd_isVisible( p_osd ) == VLC_FALSE )
388     {
389         vlc_object_release( (vlc_object_t*) p_osd );
390         return;
391     }
392
393     var_Get( p_this->p_libvlc_global, "osd_mutex", &lockval );
394     vlc_mutex_lock( lockval.p_address );
395
396     p_button = p_osd->p_state->p_visible;
397     if( p_button )
398     {
399         if( !p_button->b_range ) 
400             p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_UNSELECT );
401         if( p_button->p_prev )
402             p_osd->p_state->p_visible = p_button->p_prev;
403         else
404             p_osd->p_state->p_visible = p_osd->p_last_button;
405
406         if( !p_osd->p_state->p_visible->b_range ) 
407             p_osd->p_state->p_visible->p_current_state =
408                 osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );
409
410         osd_UpdateState( p_osd->p_state, 
411                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
412                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
413                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
414                 p_osd->p_state->p_visible->p_current_state->p_pic );
415         osd_SetMenuUpdate( p_osd, VLC_TRUE );
416     }
417 #if defined(OSD_MENU_DEBUG)
418     msg_Dbg( p_osd, "direction left [button %s]", p_osd->p_state->p_visible->psz_action );
419 #endif
420
421     vlc_object_release( (vlc_object_t*) p_osd );
422     vlc_mutex_unlock( lockval.p_address );
423 }
424
425 void __osd_MenuUp( vlc_object_t *p_this )
426 {
427     osd_menu_t *p_osd = NULL;
428     osd_button_t *p_button = NULL;
429     vlc_value_t lockval;
430 #if defined(OSD_MENU_DEBUG)
431     vlc_value_t val;
432 #endif
433
434     if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )
435     {
436         msg_Err( p_this, "osd_MenuDown failed" );
437         return;
438     }
439
440     if( osd_isVisible( p_osd ) == VLC_FALSE )
441     {
442         vlc_object_release( (vlc_object_t*) p_osd );
443         return;
444     }
445
446     var_Get( p_this->p_libvlc_global, "osd_mutex", &lockval );
447     vlc_mutex_lock( lockval.p_address );
448
449     p_button = p_osd->p_state->p_visible;
450     if( p_button )
451     {
452         if( !p_button->b_range ) 
453         {
454             p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_SELECT );
455             if( p_button->p_up )
456                 p_osd->p_state->p_visible = p_button->p_up;
457         }
458
459         if( p_button->b_range && p_osd->p_state->p_visible->b_range ) 
460         {
461             osd_state_t *p_temp = p_osd->p_state->p_visible->p_current_state;
462             if( p_temp && p_temp->p_next )
463                 p_osd->p_state->p_visible->p_current_state = p_temp->p_next;
464         }
465         else if( !p_osd->p_state->p_visible->b_range )
466         {
467             p_osd->p_state->p_visible->p_current_state =
468                 osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );
469         }
470
471         osd_UpdateState( p_osd->p_state, 
472                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
473                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
474                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
475                 p_osd->p_state->p_visible->p_current_state->p_pic );
476         osd_SetMenuUpdate( p_osd, VLC_TRUE );
477         /* If this is a range style action with associated images of only one state, 
478             * then perform "menu select" on every menu navigation
479             */
480         if( p_button->b_range ) 
481         {
482             osd_SetKeyPressed( VLC_OBJECT(p_osd->p_libvlc), config_GetInt(p_osd, p_button->psz_action) );
483 #if defined(OSD_MENU_DEBUG)
484             msg_Dbg( p_osd, "select (%d, %s)", val.i_int, p_button->psz_action );
485 #endif
486         }
487     }
488 #if defined(OSD_MENU_DEBUG)
489     msg_Dbg( p_osd, "direction up [button %s]", p_osd->p_state->p_visible->psz_action );
490 #endif
491
492     vlc_object_release( (vlc_object_t*) p_osd );
493     vlc_mutex_unlock( lockval.p_address );
494 }
495
496 void __osd_MenuDown( vlc_object_t *p_this )
497 {
498     osd_menu_t *p_osd = NULL;
499     osd_button_t *p_button = NULL;
500     vlc_value_t lockval;
501 #if defined(OSD_MENU_DEBUG)
502     vlc_value_t val;
503 #endif
504
505     if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )
506     {
507         msg_Err( p_this, "osd_MenuDown failed" );
508         return;
509     }
510
511     if( osd_isVisible( p_osd ) == VLC_FALSE )
512     {
513         vlc_object_release( (vlc_object_t*) p_osd );
514         return;
515     }
516
517     var_Get( p_this->p_libvlc_global, "osd_mutex", &lockval );
518     vlc_mutex_lock( lockval.p_address );
519
520     p_button = p_osd->p_state->p_visible;
521     if( p_button )
522     {
523         if( !p_button->b_range ) 
524         {
525             p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_SELECT );
526             if( p_button->p_down )
527                 p_osd->p_state->p_visible = p_button->p_down;
528         }
529
530         if( p_button->b_range && p_osd->p_state->p_visible->b_range ) 
531         {
532             osd_state_t *p_temp = p_osd->p_state->p_visible->p_current_state;
533             if( p_temp && p_temp->p_prev )
534                 p_osd->p_state->p_visible->p_current_state = p_temp->p_prev;
535         }
536         else if( !p_osd->p_state->p_visible->b_range )
537         {
538             p_osd->p_state->p_visible->p_current_state =
539                 osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );
540         }
541
542         osd_UpdateState( p_osd->p_state, 
543                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
544                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
545                 p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
546                 p_osd->p_state->p_visible->p_current_state->p_pic );
547         osd_SetMenuUpdate( p_osd, VLC_TRUE );
548         /* If this is a range style action with associated images of only one state,
549          * then perform "menu select" on every menu navigation
550          */
551         if( p_button->b_range ) 
552         {
553             osd_SetKeyPressed( VLC_OBJECT(p_osd->p_libvlc), config_GetInt(p_osd, p_button->psz_action_down) );
554 #if defined(OSD_MENU_DEBUG)
555             msg_Dbg( p_osd, "select (%d, %s)", val.i_int, p_button->psz_action_down );
556 #endif
557         }
558     }
559 #if defined(OSD_MENU_DEBUG)
560     msg_Dbg( p_osd, "direction down [button %s]", p_osd->p_state->p_visible->psz_action ); 
561 #endif
562
563     vlc_object_release( (vlc_object_t*) p_osd );
564     vlc_mutex_unlock( lockval.p_address );
565 }
566
567 static int osd_VolumeStep( vlc_object_t *p_this, int i_volume, int i_steps )
568 {
569     int i_volume_step = 0;
570
571     i_volume_step = config_GetInt( p_this->p_libvlc, "volume-step" );
572     return (i_volume/i_volume_step);
573 }
574
575 /**
576  * Display current audio volume bitmap
577  *
578  * The OSD Menu audio volume bar is updated to reflect the new audio volume. Call this function
579  * when the audio volume is updated outside the OSD menu command "menu up", "menu down" or "menu select".
580  */
581 void __osd_Volume( vlc_object_t *p_this )
582 {
583     osd_menu_t *p_osd = NULL;
584     osd_button_t *p_button = NULL;
585     vlc_value_t lockval;
586     int i_volume = 0;
587     int i_steps = 0;
588
589     if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )
590     {
591         msg_Err( p_this, "OSD menu volume update failed" );
592         return;
593     }
594
595     var_Get( p_this->p_libvlc_global, "osd_mutex", &lockval );
596     vlc_mutex_lock( lockval.p_address );
597
598     p_button = p_osd->p_state->p_volume;
599     if( p_osd->p_state->p_volume ) 
600         p_osd->p_state->p_visible = p_osd->p_state->p_volume;
601     if( p_button && p_button->b_range )
602     {
603         /* Update the volume state images to match the current volume */
604         i_volume = config_GetInt( p_this, "volume" );
605         i_steps = osd_VolumeStep( p_this, i_volume, p_button->i_ranges );
606         p_button->p_current_state = osd_VolumeStateChange( p_button->p_states, i_steps );
607
608         osd_UpdateState( p_osd->p_state,
609                 p_button->i_x, p_button->i_y,
610                 p_button->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
611                 p_button->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
612                 p_button->p_current_state->p_pic );
613         osd_SetMenuUpdate( p_osd, VLC_TRUE );
614         osd_SetMenuVisible( p_osd, VLC_TRUE );
615     }
616     vlc_object_release( (vlc_object_t*) p_osd );
617     vlc_mutex_unlock( lockval.p_address );
618 }