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