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