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