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