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