]> git.sesse.net Git - vlc/blob - modules/gui/macosx/controls.m
Applies part of patch from Tom Maguire. Adds controls for 1min/5min forward / backwar...
[vlc] / modules / gui / macosx / controls.m
1 /*****************************************************************************
2  * controls.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2002-2003 VideoLAN
5  * $Id$
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *          Derk-Jan Hartman <hartman at videolan dot org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>                                      /* malloc(), free() */
30 #include <sys/param.h>                                    /* for MAXPATHLEN */
31 #include <string.h>
32
33 #include "intf.h"
34 #include "vout.h"
35 #include "open.h"
36 #include "controls.h"
37 #include <osd.h>
38
39 /*****************************************************************************
40  * VLCControls implementation 
41  *****************************************************************************/
42 @implementation VLCControls
43
44 - (IBAction)play:(id)sender
45 {
46     vlc_value_t val;
47     playlist_t * p_playlist;
48     intf_thread_t * p_intf = [NSApp getIntf];
49     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
50                                                        FIND_ANYWHERE );
51
52     val.i_int = PLAYING_S;
53     if( p_input )
54     {
55         var_Get( p_input, "state", &val );
56     }
57     if( p_input && val.i_int != PAUSE_S )
58     {
59         vout_OSDMessage( p_intf, _( "Pause" ) );
60         val.i_int = PAUSE_S;
61         var_Set( p_input, "state", val );
62     }
63     else
64     {
65         p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
66                                         FIND_ANYWHERE );
67         if( p_playlist )
68         {
69             vlc_mutex_lock( &p_playlist->object_lock );
70             if( p_playlist->i_size )
71             {
72                 vlc_mutex_unlock( &p_playlist->object_lock );
73                 vout_OSDMessage( p_intf, _( "Play" ) );
74                 playlist_Play( p_playlist );
75                 vlc_object_release( p_playlist );
76             }
77             else
78             {
79                 vlc_mutex_unlock( &p_playlist->object_lock );
80                 vlc_object_release( p_playlist );
81                 [o_open openFileGeneric: nil];
82             }
83         }
84     }
85     if( p_input ) vlc_object_release( p_input );
86 }
87
88 - (IBAction)stop:(id)sender
89 {
90     intf_thread_t * p_intf = [NSApp getIntf];
91     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
92                                                        FIND_ANYWHERE );
93     if( p_playlist != NULL )
94     {
95         vout_OSDMessage( p_intf, _( "Stop" ) );
96         playlist_Stop( p_playlist );
97         vlc_object_release( p_playlist );
98     }
99 }
100
101 - (IBAction)faster:(id)sender
102 {
103     intf_thread_t * p_intf = [NSApp getIntf];
104     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
105                                                        FIND_ANYWHERE );
106     if( p_input != NULL )
107     {
108         vlc_value_t val; val.b_bool = VLC_TRUE;
109
110         var_Set( p_input, "rate-faster", val );
111         vout_OSDMessage( p_intf, _( "Faster" ) );
112         vlc_object_release( p_input );
113     }
114 }
115
116 - (IBAction)slower:(id)sender
117 {
118     intf_thread_t * p_intf = [NSApp getIntf];
119     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
120                                                        FIND_ANYWHERE );
121     if( p_input != NULL )
122     {
123         vlc_value_t val; val.b_bool = VLC_TRUE;
124
125         var_Set( p_input, "rate-slower", val );
126         vout_OSDMessage( p_intf, _( "Slower" ) );
127         vlc_object_release( p_input );
128     }
129 }
130
131 - (IBAction)prev:(id)sender
132 {
133     intf_thread_t * p_intf = [NSApp getIntf];
134     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
135                                                        FIND_ANYWHERE );
136     if( p_playlist )
137     {
138         playlist_Prev( p_playlist );
139         vlc_object_release( p_playlist );
140         vout_OSDMessage( p_intf, _( "Previous" ) );
141     }
142 }
143
144 - (IBAction)next:(id)sender
145 {
146     intf_thread_t * p_intf = [NSApp getIntf];
147     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
148                                                        FIND_ANYWHERE );
149     if( p_playlist )
150     {
151         playlist_Next( p_playlist );
152         vlc_object_release( p_playlist );
153         vout_OSDMessage( p_intf, _( "Next" ) );
154     }
155 }
156
157 - (IBAction)random:(id)sender
158 {
159     intf_thread_t * p_intf = [NSApp getIntf];
160     vlc_value_t val;
161     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
162                                                        FIND_ANYWHERE );
163     if( p_playlist == NULL )
164     {
165         return;
166     }
167
168     var_Get( p_playlist, "random", &val );
169     val.b_bool = !val.b_bool;
170     var_Set( p_playlist, "random", val );
171     if( val.b_bool )
172     {
173         vout_OSDMessage( p_intf, _( "Random On" ) );
174     }
175     else
176     {
177         vout_OSDMessage( p_intf, _( "Random Off" ) );
178     }    
179
180     p_intf->p_sys->b_playlist_update = VLC_TRUE;
181     p_intf->p_sys->b_intf_update = VLC_TRUE;
182     vlc_object_release( p_playlist );
183 }
184
185 - (IBAction)repeat:(id)sender
186 {
187     intf_thread_t * p_intf = [NSApp getIntf];
188     vlc_value_t val;
189     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
190                                                        FIND_ANYWHERE );
191     if( p_playlist == NULL )
192     {
193         return;
194     }
195
196     var_Get( p_playlist, "repeat", &val );
197     if (!val.b_bool)
198     {   
199         var_Set( p_playlist, "loop", val );
200     } 
201     val.b_bool = !val.b_bool;
202     var_Set( p_playlist, "repeat", val );
203     if( val.b_bool )
204     {
205         vout_OSDMessage( p_intf, _( "Repeat All" ) );
206     }
207     else
208     {
209         vout_OSDMessage( p_intf, _( "Repeat Off" ) );
210     }
211
212     p_intf->p_sys->b_playlist_update = VLC_TRUE;    
213     p_intf->p_sys->b_intf_update = VLC_TRUE;
214     vlc_object_release( p_playlist );
215 }
216
217 - (IBAction)loop:(id)sender
218 {
219     intf_thread_t * p_intf = [NSApp getIntf];
220     vlc_value_t val;
221     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
222                                                        FIND_ANYWHERE );
223     if( p_playlist == NULL )
224     {
225         return;
226     }
227
228     var_Get( p_playlist, "loop", &val );
229     if (!val.b_bool)
230     {
231         var_Set( p_playlist, "repeat", val );
232     }
233     val.b_bool = !val.b_bool;
234     var_Set( p_playlist, "loop", val );
235     if( val.b_bool )
236     {
237         vout_OSDMessage( p_intf, _( "Repeat One" ) );
238     }
239     else
240     {
241         vout_OSDMessage( p_intf, _( "Repeat Off" ) );
242     }    
243
244     p_intf->p_sys->b_playlist_update = VLC_TRUE;
245     p_intf->p_sys->b_intf_update = VLC_TRUE;
246     vlc_object_release( p_playlist );
247 }
248
249 - (IBAction)forward:(id)sender
250 {
251     intf_thread_t * p_intf = [NSApp getIntf];
252     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
253                                                        FIND_ANYWHERE );
254     if( p_input != NULL )
255     {
256         vlc_value_t time;
257         time.i_time = 10 * 1000000;
258         var_Set( p_input, "time-offset", time );
259         vout_OSDMessage( p_intf, _( "Jump +10 Seconds" ) );
260         vlc_object_release( p_input );
261     }
262 }
263
264 - (IBAction)forward1Min:(id)sender
265 {
266     intf_thread_t * p_intf = [NSApp getIntf];
267     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
268                                                        FIND_ANYWHERE );
269     if( p_input != NULL )
270     {
271         vlc_value_t time;
272         time.i_time = 60 * 1000000;
273         var_Set( p_input, "time-offset", time );
274         vout_OSDMessage( p_intf, _( "Jump +1 Minute" ) );
275         vlc_object_release( p_input );
276     }
277 }
278
279 - (IBAction)forward5Min:(id)sender
280 {
281     intf_thread_t * p_intf = [NSApp getIntf];
282     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
283                                                        FIND_ANYWHERE );
284     if( p_input != NULL )
285     {
286         vlc_value_t time;
287         time.i_time = 300 * 1000000;
288         var_Set( p_input, "time-offset", time );
289         vout_OSDMessage( p_intf, _( "Jump +5 Minutes" ) );
290         vlc_object_release( p_input );
291     }
292 }
293
294 - (IBAction)backward:(id)sender
295 {
296     intf_thread_t * p_intf = [NSApp getIntf];
297     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
298                                                        FIND_ANYWHERE );
299     if( p_input != NULL )
300     {
301         vlc_value_t time;
302         time.i_time = -10 * 1000000;
303         var_Set( p_input, "time-offset", time );
304         vout_OSDMessage( p_intf, _( "Jump -10 Seconds" ) );
305         vlc_object_release( p_input );
306     }
307 }
308
309 - (IBAction)backward1Min:(id)sender
310 {
311     intf_thread_t * p_intf = [NSApp getIntf];
312     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
313                                                        FIND_ANYWHERE );
314     if( p_input != NULL )
315     {
316         vlc_value_t time;
317         time.i_time = -60 * 1000000;
318         var_Set( p_input, "time-offset", time );
319         vout_OSDMessage( p_intf, _( "Jump -1 Minute" ) );
320         vlc_object_release( p_input );
321     }
322 }
323
324 - (IBAction)backward5Min:(id)sender
325 {
326     intf_thread_t * p_intf = [NSApp getIntf];
327     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
328                                                        FIND_ANYWHERE );
329     if( p_input != NULL )
330     {
331         vlc_value_t time;
332         time.i_time = -300 * 1000000;
333         var_Set( p_input, "time-offset", time );
334         vout_OSDMessage( p_intf, _( "Jump -5 Minutes" ) );
335         vlc_object_release( p_input );
336     }
337 }
338
339 - (IBAction)volumeUp:(id)sender
340 {
341     intf_thread_t * p_intf = [NSApp getIntf];
342
343     if( p_intf->p_sys->b_mute )
344     {
345         [self mute: nil];
346     }
347
348     aout_VolumeUp( p_intf, 1, NULL );
349
350     [self updateVolumeSlider];
351 }
352
353 - (IBAction)volumeDown:(id)sender
354 {
355     intf_thread_t * p_intf = [NSApp getIntf];
356
357     if( p_intf->p_sys->b_mute )
358     {
359         [self mute: nil];
360     }
361     
362     aout_VolumeDown( p_intf, 1, NULL );
363
364     [self updateVolumeSlider];
365 }
366
367 - (IBAction)mute:(id)sender
368 {
369     intf_thread_t * p_intf = [NSApp getIntf];
370     audio_volume_t i_volume;
371
372     aout_VolumeMute( p_intf, &i_volume );
373     p_intf->p_sys->b_mute = ( i_volume == 0 );
374
375     [self updateVolumeSlider];
376 }
377
378 - (IBAction)volumeSliderUpdated:(id)sender
379 {
380     intf_thread_t * p_intf = [NSApp getIntf];
381     audio_volume_t i_volume = (audio_volume_t)[sender intValue];
382
383     aout_VolumeSet( p_intf, i_volume * AOUT_VOLUME_STEP );
384 }
385
386 - (void)updateVolumeSlider
387 {
388     intf_thread_t * p_intf = [NSApp getIntf];
389     audio_volume_t i_volume;
390
391     aout_VolumeGet( p_intf, &i_volume );
392
393     [o_volumeslider setFloatValue: (float)(i_volume / AOUT_VOLUME_STEP)];
394
395     vout_OSDMessage( p_intf, "Vol %d%%", i_volume*100/AOUT_VOLUME_MAX );
396 }
397
398 - (IBAction)windowAction:(id)sender
399 {
400     id o_window = [NSApp keyWindow];
401     NSString *o_title = [sender title];
402     NSArray *o_windows = [NSApp orderedWindows];
403     NSEnumerator *o_enumerator = [o_windows objectEnumerator];
404     vout_thread_t   *p_vout = vlc_object_find( [NSApp getIntf], VLC_OBJECT_VOUT,
405                                               FIND_ANYWHERE );
406
407     if( p_vout != NULL )
408     {
409         while ((o_window = [o_enumerator nextObject]))
410         {
411             if( [[o_window className] isEqualToString: @"VLCWindow"] )
412             {
413                 if( [o_title isEqualToString: _NS("Half Size") ] )
414                     [o_window scaleWindowWithFactor: 0.5];
415                 else if( [o_title isEqualToString: _NS("Normal Size") ] )
416                     [o_window scaleWindowWithFactor: 1.0];
417                 else if( [o_title isEqualToString: _NS("Double Size") ] )
418                     [o_window scaleWindowWithFactor: 2.0];
419                 else if( [o_title isEqualToString: _NS("Float on Top") ] )
420                     [o_window toggleFloatOnTop];
421                 else if( [o_title isEqualToString: _NS("Fit to Screen") ] )
422                 {
423                     if( ![o_window isZoomed] )
424                         [o_window performZoom:self];
425                 }
426                 else
427                 {
428                     [o_window toggleFullscreen];
429                 }
430                 break;
431             }
432         }
433         vlc_object_release( (vlc_object_t *)p_vout );
434     }
435 }
436
437 - (void)setupVarMenuItem:(NSMenuItem *)o_mi
438                     target:(vlc_object_t *)p_object
439                     var:(const char *)psz_variable
440                     selector:(SEL)pf_callback
441 {
442     vlc_value_t val, text;
443     int i_type = var_Type( p_object, psz_variable );
444
445     switch( i_type & VLC_VAR_TYPE )
446     {
447     case VLC_VAR_VOID:
448     case VLC_VAR_BOOL:
449     case VLC_VAR_VARIABLE:
450     case VLC_VAR_STRING:
451     case VLC_VAR_INTEGER:
452         break;
453     default:
454         /* Variable doesn't exist or isn't handled */
455         return;
456     }
457     
458     /* Make sure we want to display the variable */
459     if( i_type & VLC_VAR_HASCHOICE )
460     {
461         var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
462         if( val.i_int == 0 ) return;
463         if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
464             return;
465     }
466     
467     /* Get the descriptive name of the variable */
468     var_Change( p_object, psz_variable, VLC_VAR_GETTEXT, &text, NULL );
469     [o_mi setTitle: [NSApp localizedString: text.psz_string ?
470                                         text.psz_string : strdup( psz_variable ) ]];
471
472     var_Get( p_object, psz_variable, &val );
473     if( i_type & VLC_VAR_HASCHOICE )
474     {
475         NSMenu *o_menu = [o_mi submenu];
476
477         [self setupVarMenu: o_menu forMenuItem: o_mi target:p_object
478                         var:psz_variable selector:pf_callback];
479         
480         if( text.psz_string ) free( text.psz_string );
481         return;
482     }
483
484     VLCMenuExt *o_data;
485     switch( i_type & VLC_VAR_TYPE )
486     {
487     case VLC_VAR_VOID:
488         o_data = [[VLCMenuExt alloc] initWithVar: psz_variable Object: p_object->i_object_id
489                 Value: val ofType: i_type];
490         [o_mi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
491         break;
492
493     case VLC_VAR_BOOL:
494         o_data = [[VLCMenuExt alloc] initWithVar: psz_variable Object: p_object->i_object_id
495                 Value: val ofType: i_type];
496         [o_mi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
497         [o_mi setState: val.b_bool ? TRUE : FALSE ];
498         break;
499
500     default:
501         if( text.psz_string ) free( text.psz_string );
502         return;
503     }
504
505     if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
506     if( text.psz_string ) free( text.psz_string );
507 }
508
509
510 - (void)setupVarMenu:(NSMenu *)o_menu
511                     forMenuItem: (NSMenuItem *)o_parent
512                     target:(vlc_object_t *)p_object
513                     var:(const char *)psz_variable
514                     selector:(SEL)pf_callback
515 {
516     vlc_value_t val, val_list, text_list;
517     int i_type, i, i_nb_items;
518
519     /* remove previous items */
520     i_nb_items = [o_menu numberOfItems];
521     for( i = 0; i < i_nb_items; i++ )
522     {
523         [o_menu removeItemAtIndex: 0];
524     }
525
526     /* Check the type of the object variable */
527     i_type = var_Type( p_object, psz_variable );
528
529     /* Make sure we want to display the variable */
530     if( i_type & VLC_VAR_HASCHOICE )
531     {
532         var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
533         if( val.i_int == 0 ) return;
534         if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
535             return;
536     }
537     else
538     {
539         return;
540     }
541
542     switch( i_type & VLC_VAR_TYPE )
543     {
544     case VLC_VAR_VOID:
545     case VLC_VAR_BOOL:
546     case VLC_VAR_VARIABLE:
547     case VLC_VAR_STRING:
548     case VLC_VAR_INTEGER:
549         break;
550     default:
551         /* Variable doesn't exist or isn't handled */
552         return;
553     }
554
555     if( var_Get( p_object, psz_variable, &val ) < 0 )
556     {
557         return;
558     }
559
560     if( var_Change( p_object, psz_variable, VLC_VAR_GETLIST,
561                     &val_list, &text_list ) < 0 )
562     {
563         if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
564         return;
565     }
566
567     /* make (un)sensitive */
568     [o_parent setEnabled: ( val_list.p_list->i_count > 1 )];
569
570     for( i = 0; i < val_list.p_list->i_count; i++ )
571     {
572         vlc_value_t another_val;
573         NSMenuItem * o_lmi;
574         NSString *o_title = @"";
575         VLCMenuExt *o_data;
576
577         switch( i_type & VLC_VAR_TYPE )
578         {
579         case VLC_VAR_VARIABLE:
580
581             /* This is causing crashes for the moment.
582             o_title = [NSApp localizedString: text_list.p_list->p_values[i].psz_string ?
583                 text_list.p_list->p_values[i].psz_string : val_list.p_list->p_values[i].psz_string ];
584             
585             o_data = [[VLCMenuExt alloc] initWithVar: strdup(psz_variable) Object: p_object->i_object_id
586                 Value: val ofType: i_type];
587             [o_lmi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
588
589             // Create a submenu
590             NSMenu *o_menu = [o_lmi submenu];
591
592             [self setupVarMenu: o_menu forMenuItem: o_lmi target:p_object
593                             var:psz_variable selector:pf_callback];
594 */
595             return;
596
597         case VLC_VAR_STRING:
598             another_val.psz_string =
599                 strdup(val_list.p_list->p_values[i].psz_string);
600
601             o_title = [NSApp localizedString: text_list.p_list->p_values[i].psz_string ?
602                 text_list.p_list->p_values[i].psz_string : val_list.p_list->p_values[i].psz_string ];
603
604             o_lmi = [o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""];
605             o_data = [[VLCMenuExt alloc] initWithVar: strdup(psz_variable) Object: p_object->i_object_id
606                     Value: another_val ofType: i_type];
607             [o_lmi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
608             [o_lmi setTarget: self];
609             
610             if( !strcmp( val.psz_string, val_list.p_list->p_values[i].psz_string ) )
611                 [o_lmi setState: TRUE ];
612
613             break;
614
615         case VLC_VAR_INTEGER:
616
617              o_title = text_list.p_list->p_values[i].psz_string ?
618                                  [NSApp localizedString: strdup( text_list.p_list->p_values[i].psz_string )] :
619                                  [NSString stringWithFormat: @"%d",
620                                  val_list.p_list->p_values[i].i_int];
621
622             o_lmi = [[o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""] retain ];
623             o_data = [[VLCMenuExt alloc] initWithVar: strdup(psz_variable) Object: p_object->i_object_id
624                     Value: val_list.p_list->p_values[i] ofType: i_type];
625             [o_lmi setRepresentedObject: [NSValue valueWithPointer:[ o_data retain]]];
626             [o_lmi setTarget: self];
627
628             if( val_list.p_list->p_values[i].i_int == val.i_int )
629                 [o_lmi setState: TRUE ];
630             break;
631
632         default:
633           break;
634         }
635     }
636     
637     /* clean up everything */
638     if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
639     var_Change( p_object, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list );
640 }
641
642 - (IBAction)toggleVar:(id)sender
643 {
644     NSMenuItem *o_mi = (NSMenuItem *)sender;
645     VLCMenuExt *o_data = [[o_mi representedObject] pointerValue];
646     [NSThread detachNewThreadSelector: @selector(toggleVarThread:)
647         toTarget: self withObject: o_data];
648
649     return;
650 }
651
652 - (int)toggleVarThread: (id)_o_data
653 {
654     vlc_object_t *p_object;
655     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
656     VLCMenuExt *o_data = (VLCMenuExt *)_o_data;
657
658     vlc_thread_set_priority( [NSApp getIntf] , VLC_THREAD_PRIORITY_LOW );
659
660     p_object = (vlc_object_t *)vlc_object_get( [NSApp getIntf],
661                                     [o_data objectID] );
662
663     if( p_object != NULL )
664     {
665         var_Set( p_object, strdup([o_data name]), [o_data value] );
666         vlc_object_release( p_object );
667         [o_pool release];
668         return VLC_TRUE;
669     }
670     [o_pool release];
671     return VLC_EGENERIC;
672 }
673
674 @end
675
676 @implementation VLCControls (NSMenuValidation)
677  
678 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
679 {
680     BOOL bEnabled = TRUE;
681     vlc_value_t val;
682     intf_thread_t * p_intf = [NSApp getIntf];
683     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
684                                                        FIND_ANYWHERE );
685
686     if( p_playlist != NULL )
687     {
688         vlc_mutex_lock( &p_playlist->object_lock );
689     }
690
691 #define p_input p_playlist->p_input
692
693     if( [[o_mi title] isEqualToString: _NS("Faster")] ||
694         [[o_mi title] isEqualToString: _NS("Slower")] )
695     {
696         if( p_playlist != NULL && p_input != NULL )
697         {
698             vlc_mutex_lock( &p_input->stream.stream_lock );
699             bEnabled = p_input->stream.b_pace_control;
700             vlc_mutex_unlock( &p_input->stream.stream_lock );
701         }
702         else
703         {
704             bEnabled = FALSE;
705         }
706     }
707     else if( [[o_mi title] isEqualToString: _NS("Stop")] )
708     {
709         if( p_playlist == NULL || p_input == NULL )
710         {
711             bEnabled = FALSE;
712         }
713     }
714     else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
715              [[o_mi title] isEqualToString: _NS("Next")] )
716     {
717         if( p_playlist == NULL )
718         {
719             bEnabled = FALSE;
720         }
721         else
722         {
723             bEnabled = p_playlist->i_size > 1;
724
725             if( p_input != NULL )
726             {
727                 vlc_mutex_lock( &p_input->stream.stream_lock );
728                 bEnabled |= p_input->stream.i_area_nb > 1;
729                 vlc_mutex_unlock( &p_input->stream.stream_lock );
730             }
731         }
732     }
733     else if( [[o_mi title] isEqualToString: _NS("Random")] )
734     {
735         int i_state;
736         var_Get( p_playlist, "random", &val );
737         i_state = val.b_bool ? NSOnState : NSOffState;
738         [o_mi setState: i_state];
739     }
740     else if( [[o_mi title] isEqualToString: _NS("Repeat One")] )
741     {
742         int i_state;
743         var_Get( p_playlist, "repeat", &val );
744         i_state = val.b_bool ? NSOnState : NSOffState;
745         [o_mi setState: i_state];
746     }
747     else if( [[o_mi title] isEqualToString: _NS("Repeat All")] )
748     {
749         int i_state;
750         var_Get( p_playlist, "loop", &val );
751         i_state = val.b_bool ? NSOnState : NSOffState;
752         [o_mi setState: i_state];
753     }
754     else if( [[o_mi title] isEqualToString: _NS("Step Forward")] ||
755              [[o_mi title] isEqualToString: _NS("Step Backward")] )
756     {
757         if( p_playlist != NULL && p_input != NULL )
758         {
759             vlc_mutex_lock( &p_input->stream.stream_lock );
760             bEnabled = p_input->stream.b_seekable;
761             vlc_mutex_unlock( &p_input->stream.stream_lock );
762         }
763         else
764         {
765             bEnabled = FALSE;
766         }
767     }
768     else if( [[o_mi title] isEqualToString: _NS("Mute")] ) 
769     {
770         [o_mi setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
771     }
772     else if( [[o_mi title] isEqualToString: _NS("Fullscreen")] ||
773                 [[o_mi title] isEqualToString: _NS("Half Size")] ||
774                 [[o_mi title] isEqualToString: _NS("Normal Size")] ||
775                 [[o_mi title] isEqualToString: _NS("Double Size")] ||
776                 [[o_mi title] isEqualToString: _NS("Fit to Screen")] ||
777                 [[o_mi title] isEqualToString: _NS("Float on Top")] )
778     {
779         id o_window;
780         NSArray *o_windows = [NSApp orderedWindows];
781         NSEnumerator *o_enumerator = [o_windows objectEnumerator];
782         bEnabled = FALSE;
783         
784         if ( [[o_mi title] isEqualToString: _NS("Float on Top")] )
785         {
786             int i_state = config_GetInt( p_playlist, "video-on-top" ) ?
787                       NSOnState : NSOffState;
788             [o_mi setState: i_state];
789         }
790         
791         vout_thread_t   *p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
792                                               FIND_ANYWHERE );
793         if( p_vout != NULL )
794         {
795             while ((o_window = [o_enumerator nextObject]))
796             {
797                 if( [[o_window className] isEqualToString: @"VLCWindow"] )
798                 {
799                     bEnabled = TRUE;
800                     break;
801                 }
802             }
803             vlc_object_release( (vlc_object_t *)p_vout );
804         }
805     }
806
807     if( p_playlist != NULL )
808     {
809         vlc_mutex_unlock( &p_playlist->object_lock );
810         vlc_object_release( p_playlist );
811     }
812
813     return( bEnabled );
814 }
815
816 @end
817
818 /*****************************************************************************
819  * VLCMenuExt implementation 
820  *****************************************************************************
821  * Object connected to a playlistitem which remembers the data belonging to
822  * the variable of the autogenerated menu
823  *****************************************************************************/
824 @implementation VLCMenuExt
825
826 - (id)initWithVar: (const char *)_psz_name Object: (int)i_id
827         Value: (vlc_value_t)val ofType: (int)_i_type
828 {
829     self = [super init];
830
831     if( self != nil )
832     {
833         psz_name = strdup( _psz_name );
834         i_object_id = i_id;
835         value = val;
836         i_type = _i_type;
837     }
838
839     return( self );
840 }
841
842 - (void)dealloc
843 {
844     free( psz_name );
845 }
846
847 - (char *)name
848 {
849     return psz_name;
850 }
851
852 - (int)objectID
853 {
854     return i_object_id;
855 }
856
857 - (vlc_value_t)value
858 {
859     return value;
860 }
861
862 - (int)type
863 {
864     return i_type;
865 }
866
867 @end