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