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