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