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