]> git.sesse.net Git - vlc/blob - src/osd/osd.c
Return 64-bits values for integer object variables
[vlc] / src / osd / osd.c
1 /*****************************************************************************
2  * osd.c - The OSD Menu core code.
3  *****************************************************************************
4  * Copyright (C) 2005-2008 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 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_keys.h>
34 #include <vlc_osd.h>
35 #include <vlc_image.h>
36
37 #include "libvlc.h"
38
39 #undef OSD_MENU_DEBUG
40
41 /*****************************************************************************
42  * Local prototypes
43  *****************************************************************************/
44
45 static void osd_UpdateState( osd_menu_state_t *, int, int, int, int, picture_t * );
46 static inline osd_state_t *osd_VolumeStateChange( osd_state_t *, int );
47 static int osd_VolumeStep( vlc_object_t *, int, int );
48 static bool osd_ParserLoad( osd_menu_t *, const char * );
49 static void osd_ParserUnload( osd_menu_t * );
50
51 static inline bool osd_isVisible( osd_menu_t *p_osd )
52 {
53     return var_GetBool( p_osd, "osd-menu-visible" );
54 }
55
56 static vlc_mutex_t *osd_GetMutex( vlc_object_t *p_this )
57 {
58     vlc_value_t lockval;
59
60     var_Create( p_this->p_libvlc, "osd_mutex", VLC_VAR_MUTEX );
61     var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
62     return lockval.p_address;
63 }
64
65 /*****************************************************************************
66  * Wrappers for loading and unloading osd parser modules.
67  *****************************************************************************/
68 static bool osd_ParserLoad( osd_menu_t *p_menu, const char *psz_file )
69 {
70     /* Stuff needed for Parser */
71     p_menu->psz_file = strdup( psz_file );
72     p_menu->p_image = image_HandlerCreate( p_menu );
73     if( !p_menu->p_image || !p_menu->psz_file )
74     {
75         msg_Err( p_menu, "unable to load images, aborting .." );
76         return false;
77     }
78     else
79     {
80         const char *psz_type;
81         const char *psz_ext = strrchr( p_menu->psz_file, '.' );
82
83         if( psz_ext && !strcmp( psz_ext, ".cfg") )
84             psz_type = "import-osd";
85         else
86             psz_type = "import-osd-xml";
87
88         p_menu->p_parser = module_need( p_menu, "osd parser",
89                                         psz_type, true );
90         if( !p_menu->p_parser )
91         {
92             return false;
93         }
94     }
95     return true;
96 }
97
98 static void osd_ParserUnload( osd_menu_t *p_menu )
99 {
100     if( p_menu->p_image )
101         image_HandlerDelete( p_menu->p_image );
102
103     if( p_menu->p_parser )
104         module_unneed( p_menu, p_menu->p_parser );
105
106     free( p_menu->psz_file );
107 }
108
109 /**
110  * Change state on an osd_button_t.
111  *
112  * This function selects the specified state and returns a pointer
113  * vlc_custom_create to it. The following states are currently supported:
114  * \see OSD_BUTTON_UNSELECT
115  * \see OSD_BUTTON_SELECT
116  * \see OSD_BUTTON_PRESSED
117  */
118 static osd_state_t *osd_StateChange( osd_button_t *p_button, const int i_state )
119 {
120     osd_state_t *p_current = p_button->p_states;
121     osd_state_t *p_temp = NULL;
122     int i = 0;
123
124     for( i= 0; p_current != NULL; i++ )
125     {
126         if( p_current->i_state == i_state )
127         {
128             p_button->i_x = p_current->i_x;
129             p_button->i_y = p_current->i_y;
130             p_button->i_width = p_current->i_width;
131             p_button->i_height = p_current->i_height;
132             return p_current;
133         }
134         p_temp = p_current->p_next;
135         p_current = p_temp;
136     }
137     return p_button->p_states;
138 }
139
140 #undef osd_MenuCreate
141 /*****************************************************************************
142  * OSD menu Funtions
143  *****************************************************************************/
144 osd_menu_t *osd_MenuCreate( vlc_object_t *p_this, const char *psz_file )
145 {
146     osd_menu_t  *p_osd = NULL;
147     vlc_value_t val;
148     vlc_mutex_t *p_lock;
149     int         i_volume = 0;
150     int         i_steps = 0;
151
152     /* to be sure to avoid multiple creation */
153     p_lock = osd_GetMutex( p_this );
154     vlc_mutex_lock( p_lock );
155
156     var_Create( p_this->p_libvlc, "osd-object", VLC_VAR_ADDRESS );
157     var_Get( p_this->p_libvlc, "osd-object", &val );
158     if( val.p_address == NULL )
159     {
160         static const char osdmenu_name[] = "osd menu";
161
162         p_osd = vlc_custom_create( p_this, sizeof( *p_osd ),
163                                    VLC_OBJECT_GENERIC, osdmenu_name );
164         if( !p_osd )
165             return NULL;
166
167         p_osd->p_parser = NULL;
168         vlc_object_attach( p_osd, p_this->p_libvlc );
169
170         /* Parse configuration file */
171         if ( !osd_ParserLoad( p_osd, psz_file ) )
172             goto error;
173         if( !p_osd->p_state )
174             goto error;
175
176         /* Setup default button (first button) */
177         p_osd->p_state->p_visible = p_osd->p_button;
178         p_osd->p_state->p_visible->p_current_state =
179             osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
180         p_osd->i_width  = p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch;
181         p_osd->i_height = p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines;
182
183         if( p_osd->p_state->p_volume )
184         {
185             /* Update the volume state images to match the current volume */
186             i_volume = config_GetInt( p_this, "volume" );
187             i_steps = osd_VolumeStep( p_this, i_volume, p_osd->p_state->p_volume->i_ranges );
188             p_osd->p_state->p_volume->p_current_state = osd_VolumeStateChange(
189                                     p_osd->p_state->p_volume->p_states, i_steps );
190         }
191         /* Initialize OSD state */
192         osd_UpdateState( p_osd->p_state, p_osd->i_x, p_osd->i_y,
193                          p_osd->i_width, p_osd->i_height, NULL );
194
195         /* Signal when an update of OSD menu is needed */
196         var_Create( p_osd, "osd-menu-update", VLC_VAR_BOOL );
197         var_Create( p_osd, "osd-menu-visible", VLC_VAR_BOOL );
198
199         var_SetBool( p_osd, "osd-menu-update", false );
200         var_SetBool( p_osd, "osd-menu-visible", false );
201
202         val.p_address = p_osd;
203         var_Set( p_this->p_libvlc, "osd-object", val );
204     }
205     else
206         p_osd = val.p_address;
207     vlc_object_hold( p_osd );
208     vlc_mutex_unlock( p_lock );
209     return p_osd;
210
211 error:
212     vlc_mutex_unlock( p_lock );
213     osd_MenuDelete( p_this, p_osd );
214     return NULL;
215 }
216
217 #undef osd_MenuDelete
218 void osd_MenuDelete( vlc_object_t *p_this, osd_menu_t *p_osd )
219 {
220     vlc_mutex_t *p_lock;
221
222     if( !p_osd || !p_this ) return;
223
224     p_lock = osd_GetMutex( p_this );
225     vlc_mutex_lock( p_lock );
226
227     if( vlc_internals( VLC_OBJECT(p_osd) )->i_refcount == 1 )
228     {
229         vlc_value_t val;
230
231         var_Destroy( p_osd, "osd-menu-visible" );
232         var_Destroy( p_osd, "osd-menu-update" );
233         osd_ParserUnload( p_osd );
234         val.p_address = NULL;
235         var_Set( p_this->p_libvlc, "osd-object", val );
236     }
237
238     vlc_object_release( p_osd );
239     vlc_mutex_unlock( p_lock );
240 }
241
242 static osd_menu_t *osd_Find( vlc_object_t *p_this )
243 {
244     vlc_value_t val;
245
246     if( var_Get( p_this->p_libvlc, "osd-object", &val ) )
247         return NULL;
248     return val.p_address;
249 }
250
251 /* The volume can be modified in another interface while the OSD Menu
252  * has not been instantiated yet. This routines updates the "volume OSD menu item"
253  * to reflect the current state of the GUI.
254  */
255 static inline osd_state_t *osd_VolumeStateChange( osd_state_t *p_current, int i_steps )
256 {
257     osd_state_t *p_temp = NULL;
258     int i;
259
260     if( i_steps < 0 ) i_steps = 0;
261
262     for( i=0; (i < i_steps) && (p_current != NULL); i++ )
263     {
264         p_temp = p_current->p_next;
265         if( !p_temp ) return p_current;
266         p_current = p_temp;
267     }
268     return (!p_temp) ? p_current : p_temp;
269 }
270
271 /* Update the state of the OSD Menu */
272 static void osd_UpdateState( osd_menu_state_t *p_state, int i_x, int i_y,
273         int i_width, int i_height, picture_t *p_pic )
274 {
275     p_state->i_x = i_x;
276     p_state->i_y = i_y;
277     p_state->i_width = i_width;
278     p_state->i_height = i_height;
279     p_state->p_pic = p_pic;
280 }
281
282 #undef osd_MenuShow
283 void osd_MenuShow( vlc_object_t *p_this )
284 {
285     osd_menu_t *p_osd;
286     osd_button_t *p_button = NULL;
287     vlc_mutex_t *p_lock = osd_GetMutex( p_this );
288
289     vlc_mutex_lock( p_lock );
290     p_osd = osd_Find( p_this );
291     if( p_osd == NULL )
292     {
293         vlc_mutex_unlock( p_lock );
294         msg_Err( p_this, "osd_MenuShow failed" );
295         return;
296     }
297
298 #if defined(OSD_MENU_DEBUG)
299     msg_Dbg( p_osd, "menu on" );
300 #endif
301     p_button = p_osd->p_state->p_visible;
302     if( p_button )
303     {
304         if( !p_button->b_range )
305             p_button->p_current_state = osd_StateChange( p_button, OSD_BUTTON_UNSELECT );
306         p_osd->p_state->p_visible = p_osd->p_button;
307
308         if( !p_osd->p_state->p_visible->b_range )
309             p_osd->p_state->p_visible->p_current_state =
310                 osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
311
312         osd_UpdateState( p_osd->p_state,
313                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
314                 p_osd->p_state->p_visible->p_current_state->i_width,
315                 p_osd->p_state->p_visible->p_current_state->i_height,
316                 p_osd->p_state->p_visible->p_current_state->p_pic );
317         osd_SetMenuUpdate( p_osd, true );
318     }
319     osd_SetMenuVisible( p_osd, true );
320
321     vlc_mutex_unlock( p_lock );
322 }
323
324 #undef osd_MenuHide
325 void osd_MenuHide( vlc_object_t *p_this )
326 {
327     osd_menu_t *p_osd;
328     vlc_mutex_t *p_lock = osd_GetMutex( p_this );
329
330     vlc_mutex_lock( p_lock );
331
332     p_osd = osd_Find( p_this );
333     if( p_osd == NULL )
334     {
335         vlc_mutex_unlock( p_lock );
336         msg_Err( p_this, "osd_MenuHide failed" );
337         return;
338     }
339
340 #if defined(OSD_MENU_DEBUG)
341     msg_Dbg( p_osd, "menu off" );
342 #endif
343     osd_UpdateState( p_osd->p_state,
344                 p_osd->p_state->i_x, p_osd->p_state->i_y,
345                 0, 0, NULL );
346     osd_SetMenuUpdate( p_osd, true );
347
348     vlc_mutex_unlock( p_lock );
349 }
350
351 #undef osd_MenuActivate
352 void osd_MenuActivate( vlc_object_t *p_this )
353 {
354     osd_menu_t *p_osd;
355     osd_button_t *p_button = NULL;
356     vlc_mutex_t *p_lock = osd_GetMutex( p_this );
357
358     vlc_mutex_lock( p_lock );
359
360     p_osd = osd_Find( p_this );
361     if( p_osd == NULL || !osd_isVisible( p_osd ) )
362     {
363         vlc_mutex_unlock( p_lock );
364         msg_Err( p_this, "osd_MenuActivate failed" );
365         return;
366     }
367
368 #if defined(OSD_MENU_DEBUG)
369     msg_Dbg( p_osd, "select" );
370 #endif
371     p_button = p_osd->p_state->p_visible;
372     /*
373      * Is there a menu item above or below? If so, then select it.
374      */
375     if( p_button && p_button->p_up )
376     {
377         vlc_mutex_unlock( p_lock );
378         osd_MenuUp( p_this );   /* "menu select" means go to menu item above. */
379         return;
380     }
381     if( p_button && p_button->p_down )
382     {
383         vlc_mutex_unlock( p_lock );
384         osd_MenuDown( p_this ); /* "menu select" means go to menu item below. */
385         return;
386     }
387
388     if( p_button && !p_button->b_range )
389     {
390         p_button->p_current_state = osd_StateChange( p_button, OSD_BUTTON_PRESSED );
391         osd_UpdateState( p_osd->p_state,
392                 p_button->i_x, p_button->i_y,
393                 p_osd->p_state->p_visible->p_current_state->i_width,
394                 p_osd->p_state->p_visible->p_current_state->i_height,
395                 p_button->p_current_state->p_pic );
396         osd_SetMenuUpdate( p_osd, true );
397         osd_SetMenuVisible( p_osd, true );
398         osd_SetKeyPressed( VLC_OBJECT(p_osd->p_libvlc),
399                            var_InheritInteger( p_osd, p_button->psz_action ) );
400 #if defined(OSD_MENU_DEBUG)
401         msg_Dbg( p_osd, "select (%d, %s)",
402                  (int)var_InheritInteger( p_osd, p_button->psz_action ),
403                  p_button->psz_action );
404 #endif
405     }
406     vlc_mutex_unlock( p_lock );
407 }
408
409 #undef osd_MenuNext
410 void osd_MenuNext( vlc_object_t *p_this )
411 {
412     osd_menu_t *p_osd;
413     osd_button_t *p_button = NULL;
414     vlc_mutex_t *p_lock = osd_GetMutex( p_this );
415
416     vlc_mutex_lock( p_lock );
417
418     p_osd = osd_Find( p_this );
419     if( p_osd == NULL || !osd_isVisible( p_osd ) )
420     {
421         vlc_mutex_unlock( p_lock );
422         msg_Err( p_this, "osd_MenuNext failed" );
423         return;
424     }
425
426     p_button = p_osd->p_state->p_visible;
427     if( p_button )
428     {
429         if( !p_button->b_range )
430             p_button->p_current_state = osd_StateChange( p_button, OSD_BUTTON_UNSELECT );
431         if( p_button->p_next )
432             p_osd->p_state->p_visible = p_button->p_next;
433         else
434             p_osd->p_state->p_visible = p_osd->p_button;
435
436         if( !p_osd->p_state->p_visible->b_range )
437             p_osd->p_state->p_visible->p_current_state =
438                 osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
439
440         osd_UpdateState( p_osd->p_state,
441                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
442                 p_osd->p_state->p_visible->p_current_state->i_width,
443                 p_osd->p_state->p_visible->p_current_state->i_height,
444                 p_osd->p_state->p_visible->p_current_state->p_pic );
445         osd_SetMenuUpdate( p_osd, true );
446     }
447 #if defined(OSD_MENU_DEBUG)
448     msg_Dbg( p_osd, "direction right [button %s]", p_osd->p_state->p_visible->psz_action );
449 #endif
450
451     vlc_mutex_unlock( p_lock );
452 }
453
454 #undef osd_MenuPrev
455 void osd_MenuPrev( vlc_object_t *p_this )
456 {
457     osd_menu_t *p_osd;
458     osd_button_t *p_button = NULL;
459     vlc_mutex_t *p_lock = osd_GetMutex( p_this );
460
461     vlc_mutex_lock( p_lock );
462     p_osd = osd_Find( p_this );
463     if( p_osd == NULL || !osd_isVisible( p_osd ) )
464     {
465         vlc_mutex_unlock( p_lock );
466         msg_Err( p_this, "osd_MenuPrev failed" );
467         return;
468     }
469
470     p_button = p_osd->p_state->p_visible;
471     if( p_button )
472     {
473         if( !p_button->b_range )
474             p_button->p_current_state = osd_StateChange( p_button, OSD_BUTTON_UNSELECT );
475         if( p_button->p_prev )
476             p_osd->p_state->p_visible = p_button->p_prev;
477         else
478             p_osd->p_state->p_visible = p_osd->p_last_button;
479
480         if( !p_osd->p_state->p_visible->b_range )
481             p_osd->p_state->p_visible->p_current_state =
482                 osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
483
484         osd_UpdateState( p_osd->p_state,
485                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
486                 p_osd->p_state->p_visible->p_current_state->i_width,
487                 p_osd->p_state->p_visible->p_current_state->i_height,
488                 p_osd->p_state->p_visible->p_current_state->p_pic );
489         osd_SetMenuUpdate( p_osd, true );
490     }
491 #if defined(OSD_MENU_DEBUG)
492     msg_Dbg( p_osd, "direction left [button %s]", p_osd->p_state->p_visible->psz_action );
493 #endif
494
495     vlc_mutex_unlock( p_lock );
496 }
497
498 #undef osd_MenuUp
499 void osd_MenuUp( vlc_object_t *p_this )
500 {
501     osd_menu_t *p_osd;
502     osd_button_t *p_button = NULL;
503 #if defined(OSD_MENU_DEBUG)
504     vlc_value_t val;
505 #endif
506     vlc_mutex_t *p_lock = osd_GetMutex( p_this );
507
508     vlc_mutex_lock( p_lock );
509     p_osd = osd_Find( p_this );
510     if( p_osd == NULL || !osd_isVisible( p_osd ) )
511     {
512         vlc_mutex_unlock( p_lock );
513         msg_Err( p_this, "osd_MenuActivate failed" );
514         return;
515     }
516
517     p_button = p_osd->p_state->p_visible;
518     if( p_button )
519     {
520         if( !p_button->b_range )
521         {
522             p_button->p_current_state = osd_StateChange( p_button, OSD_BUTTON_SELECT );
523             if( p_button->p_up )
524                 p_osd->p_state->p_visible = p_button->p_up;
525         }
526
527         if( p_button->b_range && p_osd->p_state->p_visible->b_range )
528         {
529             osd_state_t *p_temp = p_osd->p_state->p_visible->p_current_state;
530             if( p_temp && p_temp->p_next )
531                 p_osd->p_state->p_visible->p_current_state = p_temp->p_next;
532         }
533         else if( !p_osd->p_state->p_visible->b_range )
534         {
535             p_osd->p_state->p_visible->p_current_state =
536                 osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
537         }
538
539         osd_UpdateState( p_osd->p_state,
540                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
541                 p_osd->p_state->p_visible->p_current_state->i_width,
542                 p_osd->p_state->p_visible->p_current_state->i_height,
543                 p_osd->p_state->p_visible->p_current_state->p_pic );
544         osd_SetMenuUpdate( p_osd, true );
545         /* If this is a range style action with associated images of only one state,
546             * then perform "menu select" on every menu navigation
547             */
548         if( p_button->b_range )
549         {
550             osd_SetKeyPressed( VLC_OBJECT(p_osd->p_libvlc),
551                                var_InheritInteger(p_osd, p_button->psz_action) );
552 #if defined(OSD_MENU_DEBUG)
553             msg_Dbg( p_osd, "select (%"PRId64", %s)", val.i_int, p_button->psz_action );
554 #endif
555         }
556     }
557 #if defined(OSD_MENU_DEBUG)
558     msg_Dbg( p_osd, "direction up [button %s]", p_osd->p_state->p_visible->psz_action );
559 #endif
560
561     vlc_mutex_unlock( p_lock );
562 }
563
564 #undef osd_MenuDown
565 void osd_MenuDown( vlc_object_t *p_this )
566 {
567     osd_menu_t *p_osd;
568     osd_button_t *p_button = NULL;
569 #if defined(OSD_MENU_DEBUG)
570     vlc_value_t val;
571 #endif
572     vlc_mutex_t *p_lock = osd_GetMutex( p_this );
573
574     vlc_mutex_lock( p_lock );
575
576     p_osd = osd_Find( p_this );
577     if( p_osd == NULL || !osd_isVisible( p_osd ) )
578     {
579         vlc_mutex_unlock( p_lock );
580         msg_Err( p_this, "osd_MenuActivate failed" );
581         return;
582     }
583
584     p_button = p_osd->p_state->p_visible;
585     if( p_button )
586     {
587         if( !p_button->b_range )
588         {
589             p_button->p_current_state = osd_StateChange( p_button, OSD_BUTTON_SELECT );
590             if( p_button->p_down )
591                 p_osd->p_state->p_visible = p_button->p_down;
592         }
593
594         if( p_button->b_range && p_osd->p_state->p_visible->b_range )
595         {
596             osd_state_t *p_temp = p_osd->p_state->p_visible->p_current_state;
597             if( p_temp && p_temp->p_prev )
598                 p_osd->p_state->p_visible->p_current_state = p_temp->p_prev;
599         }
600         else if( !p_osd->p_state->p_visible->b_range )
601         {
602             p_osd->p_state->p_visible->p_current_state =
603                 osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
604         }
605
606         osd_UpdateState( p_osd->p_state,
607                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
608                 p_osd->p_state->p_visible->p_current_state->i_width,
609                 p_osd->p_state->p_visible->p_current_state->i_height,
610                 p_osd->p_state->p_visible->p_current_state->p_pic );
611         osd_SetMenuUpdate( p_osd, true );
612         /* If this is a range style action with associated images of only one state,
613          * then perform "menu select" on every menu navigation
614          */
615         if( p_button->b_range )
616         {
617             osd_SetKeyPressed( VLC_OBJECT(p_osd->p_libvlc),
618                                var_InheritInteger(p_osd, p_button->psz_action_down) );
619 #if defined(OSD_MENU_DEBUG)
620             msg_Dbg( p_osd, "select (%"PRId64", %s)", val.i_int, p_button->psz_action_down );
621 #endif
622         }
623     }
624 #if defined(OSD_MENU_DEBUG)
625     msg_Dbg( p_osd, "direction down [button %s]", p_osd->p_state->p_visible->psz_action );
626 #endif
627
628     vlc_mutex_unlock( p_lock );
629 }
630
631 static int osd_VolumeStep( vlc_object_t *p_this, int i_volume, int i_steps )
632 {
633     int i_volume_step = 0;
634     (void)i_steps;
635
636     i_volume_step = config_GetInt( p_this->p_libvlc, "volume-step" );
637     return (i_volume/i_volume_step);
638 }
639
640 #undef osd_Volume
641 /**
642  * Display current audio volume bitmap
643  *
644  * The OSD Menu audio volume bar is updated to reflect the new audio volume. Call this function
645  * when the audio volume is updated outside the OSD menu command "menu up", "menu down" or "menu select".
646  */
647 void osd_Volume( vlc_object_t *p_this )
648 {
649     osd_menu_t *p_osd;
650     osd_button_t *p_button = NULL;
651     vlc_mutex_t *p_lock = osd_GetMutex( p_this );
652     int i_volume = 0;
653     int i_steps = 0;
654
655     vlc_mutex_lock( p_lock );
656
657     p_osd = osd_Find( p_this );
658     if( p_osd == NULL )
659     {
660         vlc_mutex_unlock( p_lock );
661         msg_Err( p_this, "OSD menu volume update failed" );
662         return;
663     }
664
665     if( p_osd->p_state && p_osd->p_state->p_volume )
666     {
667
668         p_button = p_osd->p_state->p_volume;
669         if( p_osd->p_state->p_volume )
670             p_osd->p_state->p_visible = p_osd->p_state->p_volume;
671         if( p_button && p_button->b_range )
672         {
673             /* Update the volume state images to match the current volume */
674             i_volume = config_GetInt( p_this, "volume" );
675             i_steps = osd_VolumeStep( p_this, i_volume, p_button->i_ranges );
676             p_button->p_current_state = osd_VolumeStateChange( p_button->p_states, i_steps );
677
678             osd_UpdateState( p_osd->p_state,
679                     p_button->i_x, p_button->i_y,
680                     p_button->p_current_state->i_width,
681                     p_button->p_current_state->i_height,
682                     p_button->p_current_state->p_pic );
683             osd_SetMenuUpdate( p_osd, true );
684             osd_SetMenuVisible( p_osd, true );
685         }
686     }
687     vlc_mutex_unlock( p_lock );
688 }
689
690 #undef osd_ButtonFind
691 osd_button_t *osd_ButtonFind( vlc_object_t *p_this, int i_x, int i_y,
692     int i_window_height, int i_window_width,
693     int i_scale_width, int i_scale_height )
694 {
695     osd_menu_t *p_osd;
696     osd_button_t *p_button;
697     vlc_mutex_t *p_lock = osd_GetMutex( p_this );
698
699     vlc_mutex_lock( p_lock );
700
701     p_osd = osd_Find( p_this );
702     if( p_osd == NULL || !osd_isVisible( p_osd ) )
703     {
704         vlc_mutex_unlock( p_lock );
705         msg_Err( p_this, "osd_ButtonFind failed" );
706         return NULL;
707     }
708
709     p_button = p_osd->p_button;
710     for( ; p_button != NULL; p_button = p_button->p_next )
711     {
712         int i_source_video_width  = ( i_window_width  * 1000 ) / i_scale_width;
713         int i_source_video_height = ( i_window_height * 1000 ) / i_scale_height;
714         int i_y_offset = p_button->i_y;
715         int i_x_offset = p_button->i_x;
716         int i_width = p_button->i_width;
717         int i_height = p_button->i_height;
718
719         if( p_osd->i_position > 0 )
720         {
721             int i_inv_scale_y = i_source_video_height;
722             int i_inv_scale_x = i_source_video_width;
723             int pi_x = 0;
724
725             if( p_osd->i_position & SUBPICTURE_ALIGN_BOTTOM )
726             {
727                 i_y_offset = i_window_height - p_button->i_height -
728                     (p_osd->i_y + p_button->i_y) * i_inv_scale_y / 1000;
729             }
730             else if ( !(p_osd->i_position & SUBPICTURE_ALIGN_TOP) )
731             {
732                 i_y_offset = i_window_height / 2 - p_button->i_height / 2;
733             }
734
735             if( p_osd->i_position & SUBPICTURE_ALIGN_RIGHT )
736             {
737                 i_x_offset = i_window_width - p_button->i_width -
738                     (pi_x + p_button->i_x)
739                     * i_inv_scale_x / 1000;
740             }
741             else if ( !(p_osd->i_position & SUBPICTURE_ALIGN_LEFT) )
742             {
743                 i_x_offset = i_window_width / 2 - p_button->i_width / 2;
744             }
745
746             i_width = i_window_width - p_button->i_width - i_inv_scale_x / 1000;
747             i_height = i_window_height - p_button->i_height - i_inv_scale_y / 1000;
748         }
749
750         // TODO: write for Up / Down case too.
751         // TODO: handle absolute positioning case
752         if( ( i_x >= i_x_offset ) && ( i_x <= i_x_offset + i_width ) &&
753             ( i_y >= i_y_offset ) && ( i_y <= i_y_offset + i_height ) )
754         {
755             vlc_mutex_unlock( p_lock );
756             return p_button;
757         }
758     }
759
760     vlc_mutex_unlock( p_lock );
761     return NULL;
762 }
763
764 #undef osd_ButtonSelect
765 /**
766  * Select the button provided as the new active button
767  */
768 void osd_ButtonSelect( vlc_object_t *p_this, osd_button_t *p_button )
769 {
770     osd_menu_t *p_osd;
771     osd_button_t *p_old;
772     vlc_mutex_t *p_lock = osd_GetMutex( p_this );
773
774     vlc_mutex_lock( p_lock );
775
776     p_osd = osd_Find( p_this );
777     if( p_osd == NULL || !osd_isVisible( p_osd ) )
778     {
779         vlc_mutex_unlock( p_lock );
780         msg_Err( p_this, "osd_ButtonSelect failed" );
781         return;
782     }
783
784     p_old = p_osd->p_state->p_visible;
785     if( p_old )
786     {
787         if( !p_old->b_range )
788             p_old->p_current_state = osd_StateChange( p_old, OSD_BUTTON_UNSELECT );
789         p_osd->p_state->p_visible = p_button;
790
791         if( !p_osd->p_state->p_visible->b_range )
792             p_osd->p_state->p_visible->p_current_state =
793                 osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
794
795         osd_UpdateState( p_osd->p_state,
796                 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
797                 p_osd->p_state->p_visible->p_current_state->i_width,
798                 p_osd->p_state->p_visible->p_current_state->i_height,
799                 p_osd->p_state->p_visible->p_current_state->p_pic );
800         osd_SetMenuUpdate( p_osd, true );
801     }
802 #if defined(OSD_MENU_DEBUG)
803     msg_Dbg( p_osd, "button selected is [button %s]", p_osd->p_state->p_visible->psz_action );
804 #endif
805
806     vlc_mutex_unlock( p_lock );
807 }