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