]> git.sesse.net Git - vlc/blob - modules/gui/macosx/misc.m
macosx: removed tabs and fixed whitespacing errors
[vlc] / modules / gui / macosx / misc.m
1 /*****************************************************************************
2  * misc.m: code not specific to vlc
3  *****************************************************************************
4  * Copyright (C) 2003-2011 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Felix Paul Kühne <fkuehne at videolan dot org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #import <Cocoa/Cocoa.h>
26 #import <Carbon/Carbon.h>
27
28 #import "CompatibilityFixes.h"
29 #import "intf.h"                                          /* VLCApplication */
30 #import "MainWindow.h"
31 #import "misc.h"
32 #import "playlist.h"
33 #import "controls.h"
34 #import <vlc_url.h>
35
36 /*****************************************************************************
37  * NSAnimation (VLCAdditions)
38  *
39  *  Missing extension to NSAnimation
40  *****************************************************************************/
41
42 @implementation NSAnimation (VLCAdditions)
43 /* fake class attributes  */
44 static NSMapTable *VLCAdditions_userInfo = NULL;
45
46 + (void)load
47 {
48     /* init our fake object attribute */
49     VLCAdditions_userInfo = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 16);
50 }
51
52 - (void)dealloc
53 {
54     NSMapRemove(VLCAdditions_userInfo, self);
55     [super dealloc];
56 }
57
58 - (void)setUserInfo: (void *)userInfo
59 {
60     NSMapInsert(VLCAdditions_userInfo, self, (void*)userInfo);
61 }
62
63 - (void *)userInfo
64 {
65     return NSMapGet(VLCAdditions_userInfo, self);
66 }
67 @end
68
69 /*****************************************************************************
70  * NSScreen (VLCAdditions)
71  *
72  *  Missing extension to NSScreen
73  *****************************************************************************/
74
75 @implementation NSScreen (VLCAdditions)
76
77 static NSMutableArray *blackoutWindows = NULL;
78
79 + (void)load
80 {
81     /* init our fake object attribute */
82     blackoutWindows = [[NSMutableArray alloc] initWithCapacity:1];
83 }
84
85 + (NSScreen *)screenWithDisplayID: (CGDirectDisplayID)displayID
86 {
87     NSUInteger count = [[NSScreen screens] count];
88
89     for( NSUInteger i = 0; i < count; i++ )
90     {
91         NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
92         if([screen displayID] == displayID)
93             return screen;
94     }
95     return nil;
96 }
97
98 - (BOOL)isMainScreen
99 {
100     return ([self displayID] == [[[NSScreen screens] objectAtIndex:0] displayID]);
101 }
102
103 - (BOOL)isScreen: (NSScreen*)screen
104 {
105     return ([self displayID] == [screen displayID]);
106 }
107
108 - (CGDirectDisplayID)displayID
109 {
110     return (CGDirectDisplayID)[[[self deviceDescription] objectForKey: @"NSScreenNumber"] intValue];
111 }
112
113 - (void)blackoutOtherScreens
114 {
115     /* Free our previous blackout window (follow blackoutWindow alloc strategy) */
116     [blackoutWindows makeObjectsPerformSelector:@selector(close)];
117     [blackoutWindows removeAllObjects];
118
119     NSUInteger screenCount = [[NSScreen screens] count];
120     for(NSUInteger i = 0; i < screenCount; i++)
121     {
122         NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
123         VLCWindow *blackoutWindow;
124         NSRect screen_rect;
125
126         if([self isScreen: screen])
127             continue;
128
129         screen_rect = [screen frame];
130         screen_rect.origin.x = screen_rect.origin.y = 0;
131
132         /* blackoutWindow alloc strategy
133             - The NSMutableArray blackoutWindows has the blackoutWindow references
134             - blackoutOtherDisplays is responsible for alloc/releasing its Windows
135         */
136         blackoutWindow = [[VLCWindow alloc] initWithContentRect: screen_rect styleMask: NSBorderlessWindowMask
137                 backing: NSBackingStoreBuffered defer: NO screen: screen];
138         [blackoutWindow setBackgroundColor:[NSColor blackColor]];
139         [blackoutWindow setLevel: NSFloatingWindowLevel]; /* Disappear when Expose is triggered */
140
141         [blackoutWindow displayIfNeeded];
142         [blackoutWindow orderFront: self animate: YES];
143
144         [blackoutWindows addObject: blackoutWindow];
145         [blackoutWindow release];
146
147         if( [screen isMainScreen] )
148         {
149             if (OSX_LEOPARD)
150                 SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
151             else
152                 [NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
153         }
154     }
155 }
156
157 + (void)unblackoutScreens
158 {
159     NSUInteger blackoutWindowCount = [blackoutWindows count];
160
161     for(NSUInteger i = 0; i < blackoutWindowCount; i++)
162     {
163         VLCWindow *blackoutWindow = [blackoutWindows objectAtIndex: i];
164         [blackoutWindow closeAndAnimate: YES];
165     }
166
167     if (OSX_LEOPARD)
168         SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
169     else
170         [NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
171 }
172
173 @end
174
175 /*****************************************************************************
176  * VLCWindow
177  *
178  *  Missing extension to NSWindow
179  *****************************************************************************/
180
181 @implementation VLCWindow
182 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
183     backing:(NSBackingStoreType)backingType defer:(BOOL)flag
184 {
185     self = [super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag];
186     if( self )
187     {
188         b_isFullscreen = NO;
189         b_isset_canBecomeKeyWindow = NO;
190         /* we don't want this window to be restored on relaunch */
191         if (OSX_LION)
192             [self setRestorable:NO];
193     }
194     return self;
195 }
196 - (void)setCanBecomeKeyWindow: (BOOL)canBecomeKey
197 {
198     b_isset_canBecomeKeyWindow = YES;
199     b_canBecomeKeyWindow = canBecomeKey;
200 }
201
202 - (BOOL)canBecomeKeyWindow
203 {
204     if(b_isset_canBecomeKeyWindow)
205         return b_canBecomeKeyWindow;
206
207     return [super canBecomeKeyWindow];
208 }
209
210 - (void)closeAndAnimate: (BOOL)animate
211 {
212     NSInvocation *invoc;
213
214     if (!animate)
215     {
216         [super close];
217         return;
218     }
219
220     invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(close)]];
221     [invoc setTarget: self];
222
223     if (![self isVisible] || [self alphaValue] == 0.0)
224     {
225         [super close];
226         return;
227     }
228
229     [self orderOut: self animate: YES callback: invoc];
230 }
231
232 - (void)orderOut: (id)sender animate: (BOOL)animate
233 {
234     NSInvocation *invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(orderOut:)]];
235     [invoc setTarget: self];
236     [invoc setArgument: sender atIndex: 0];
237     [self orderOut: sender animate: animate callback: invoc];
238 }
239
240 - (void)orderOut: (id)sender animate: (BOOL)animate callback:(NSInvocation *)callback
241 {
242     NSViewAnimation *anim;
243     NSViewAnimation *current_anim;
244     NSMutableDictionary *dict;
245
246     if (!animate)
247     {
248         [self orderOut: sender];
249         return;
250     }
251
252     dict = [[NSMutableDictionary alloc] initWithCapacity:2];
253
254     [dict setObject:self forKey:NSViewAnimationTargetKey];
255
256     [dict setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
257     anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
258     [dict release];
259
260     [anim setAnimationBlockingMode:NSAnimationNonblocking];
261     [anim setDuration:0.9];
262     [anim setFrameRate:30];
263     [anim setUserInfo: callback];
264
265     @synchronized(self) {
266         current_anim = self->animation;
267
268         if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeOutEffect && [current_anim isAnimating])
269         {
270             [anim release];
271         }
272         else
273         {
274             if (current_anim)
275             {
276                 [current_anim stopAnimation];
277                 [anim setCurrentProgress:1.0-[current_anim currentProgress]];
278                 [current_anim release];
279             }
280             else
281                 [anim setCurrentProgress:1.0 - [self alphaValue]];
282             self->animation = anim;
283             [self setDelegate: self];
284             [anim startAnimation];
285         }
286     }
287 }
288
289 - (void)orderFront: (id)sender animate: (BOOL)animate
290 {
291     NSViewAnimation *anim;
292     NSViewAnimation *current_anim;
293     NSMutableDictionary *dict;
294
295     if (!animate)
296     {
297         [super orderFront: sender];
298         [self setAlphaValue: 1.0];
299         return;
300     }
301
302     if (![self isVisible])
303     {
304         [self setAlphaValue: 0.0];
305         [super orderFront: sender];
306     }
307     else if ([self alphaValue] == 1.0)
308     {
309         [super orderFront: self];
310         return;
311     }
312
313     dict = [[NSMutableDictionary alloc] initWithCapacity:2];
314
315     [dict setObject:self forKey:NSViewAnimationTargetKey];
316
317     [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
318     anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
319     [dict release];
320
321     [anim setAnimationBlockingMode:NSAnimationNonblocking];
322     [anim setDuration:0.5];
323     [anim setFrameRate:30];
324
325     @synchronized(self) {
326         current_anim = self->animation;
327
328         if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeInEffect && [current_anim isAnimating])
329         {
330             [anim release];
331         }
332         else
333         {
334             if (current_anim)
335             {
336                 [current_anim stopAnimation];
337                 [anim setCurrentProgress:1.0 - [current_anim currentProgress]];
338                 [current_anim release];
339             }
340             else
341                 [anim setCurrentProgress:[self alphaValue]];
342             self->animation = anim;
343             [self setDelegate: self];
344             [self orderFront: sender];
345             [anim startAnimation];
346         }
347     }
348 }
349
350 - (void)animationDidEnd:(NSAnimation*)anim
351 {
352     if ([self alphaValue] <= 0.0)
353     {
354         NSInvocation * invoc;
355         [super orderOut: nil];
356         [self setAlphaValue: 1.0];
357         if ((invoc = [anim userInfo]))
358             [invoc invoke];
359     }
360 }
361
362 - (void)setFullscreen:(BOOL)b_var
363 {
364     b_isFullscreen = b_var;
365 }
366
367 - (BOOL)isFullscreen
368 {
369     return b_isFullscreen;
370 }
371
372 @end
373
374 /*****************************************************************************
375  * VLCControllerView
376  *****************************************************************************/
377
378 @implementation VLCControllerView
379
380 - (void)dealloc
381 {
382     [self unregisterDraggedTypes];
383     [super dealloc];
384 }
385
386 - (void)awakeFromNib
387 {
388     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
389         NSFilenamesPboardType, nil]];
390 }
391
392 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
393 {
394     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
395                 == NSDragOperationGeneric)
396     {
397         return NSDragOperationGeneric;
398     }
399     else
400     {
401         return NSDragOperationNone;
402     }
403 }
404
405 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
406 {
407     return YES;
408 }
409
410 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
411 {
412     NSPasteboard *o_paste = [sender draggingPasteboard];
413     NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
414     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
415     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
416
417     if( o_carried_data )
418     {
419         if ([o_desired_type isEqualToString:NSFilenamesPboardType])
420         {
421             NSArray *o_array = [NSArray array];
422             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
423             NSUInteger count = [o_values count];
424
425             input_thread_t * p_input = pl_CurrentInput( VLCIntf );
426             BOOL b_returned = NO;
427
428             if (count == 1 && p_input)
429             {
430                 b_returned = input_AddSubtitle( p_input, make_URI([[o_values objectAtIndex:0] UTF8String], NULL), true );
431                 vlc_object_release( p_input );
432                 if(!b_returned)
433                     return YES;
434             }
435             else if( p_input )
436                 vlc_object_release( p_input );
437
438             for( NSUInteger i = 0; i < count; i++)
439             {
440                 NSDictionary *o_dic;
441                 char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], NULL);
442                 if( !psz_uri )
443                     continue;
444
445                 o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
446
447                 free( psz_uri );
448                 o_array = [o_array arrayByAddingObject: o_dic];
449             }
450             [(VLCPlaylist *)[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
451             return YES;
452         }
453     }
454     [self setNeedsDisplay:YES];
455     return YES;
456 }
457
458 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
459 {
460     [self setNeedsDisplay:YES];
461 }
462
463 @end
464
465 /*****************************************************************************
466  * VLBrushedMetalImageView
467  *****************************************************************************/
468
469 @implementation VLBrushedMetalImageView
470
471 - (BOOL)mouseDownCanMoveWindow
472 {
473     return YES;
474 }
475
476 - (void)dealloc
477 {
478     [self unregisterDraggedTypes];
479     [super dealloc];
480 }
481
482 - (void)awakeFromNib
483 {
484     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
485         NSFilenamesPboardType, nil]];
486     [self setImageScaling: NSScaleToFit];
487     [self setImageFrameStyle: NSImageFrameNone];
488     [self setImageAlignment: NSImageAlignCenter];
489 }
490
491 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
492 {
493     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
494                 == NSDragOperationGeneric)
495     {
496         return NSDragOperationGeneric;
497     }
498     else
499     {
500         return NSDragOperationNone;
501     }
502 }
503
504 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
505 {
506     return YES;
507 }
508
509 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
510 {
511     NSPasteboard *o_paste = [sender draggingPasteboard];
512     NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
513     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
514     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
515     BOOL b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
516
517     if( o_carried_data )
518     {
519         if ([o_desired_type isEqualToString:NSFilenamesPboardType])
520         {
521             NSArray *o_array = [NSArray array];
522             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
523             NSUInteger count = [o_values count];
524
525             input_thread_t * p_input = pl_CurrentInput( VLCIntf );
526             BOOL b_returned = NO;
527
528             if (count == 1 && p_input)
529             {
530                 b_returned = input_AddSubtitle( p_input, make_URI([[o_values objectAtIndex:0] UTF8String], NULL), true );
531                 vlc_object_release( p_input );
532                 if(!b_returned)
533                     return YES;
534             }
535             else if( p_input )
536                 vlc_object_release( p_input );
537
538             for( NSUInteger i = 0; i < count; i++)
539             {
540                 NSDictionary *o_dic;
541                 char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], NULL);
542                 if( !psz_uri )
543                     continue;
544
545                 o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
546                 free( psz_uri );
547
548                 o_array = [o_array arrayByAddingObject: o_dic];
549             }
550             if( b_autoplay )
551                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
552             else
553                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
554             return YES;
555         }
556     }
557     [self setNeedsDisplay:YES];
558     return YES;
559 }
560
561 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
562 {
563     [self setNeedsDisplay:YES];
564 }
565
566 @end
567
568
569 /*****************************************************************************
570  * MPSlider
571  *****************************************************************************/
572 @implementation MPSlider
573
574 void _drawKnobInRect(NSRect knobRect)
575 {
576     // Center knob in given rect
577     knobRect.origin.x += (int)((float)(knobRect.size.width - 7)/2.0);
578     knobRect.origin.y += (int)((float)(knobRect.size.height - 7)/2.0);
579
580     // Draw diamond
581     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 6, 1, 1), NSCompositeSourceOver);
582     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 5, 3, 1), NSCompositeSourceOver);
583     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 4, 5, 1), NSCompositeSourceOver);
584     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 0, knobRect.origin.y + 3, 7, 1), NSCompositeSourceOver);
585     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 2, 5, 1), NSCompositeSourceOver);
586     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 1, 3, 1), NSCompositeSourceOver);
587     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 0, 1, 1), NSCompositeSourceOver);
588 }
589
590 void _drawFrameInRect(NSRect frameRect)
591 {
592     // Draw frame
593     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, 1), NSCompositeSourceOver);
594     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y + frameRect.size.height-1, frameRect.size.width, 1), NSCompositeSourceOver);
595     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
596     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x+frameRect.size.width-1, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
597 }
598
599 - (void)drawRect:(NSRect)rect
600 {
601     // Draw default to make sure the slider behaves correctly
602     [[NSGraphicsContext currentContext] saveGraphicsState];
603     NSRectClip(NSZeroRect);
604     [super drawRect:rect];
605     [[NSGraphicsContext currentContext] restoreGraphicsState];
606
607     // Full size
608     rect = [self bounds];
609     int diff = (int)(([[self cell] knobThickness] - 7.0)/2.0) - 1;
610     rect.origin.x += diff-1;
611     rect.origin.y += diff;
612     rect.size.width -= 2*diff-2;
613     rect.size.height -= 2*diff;
614
615     // Draw dark
616     NSRect knobRect = [[self cell] knobRectFlipped:NO];
617     [[[NSColor blackColor] colorWithAlphaComponent:0.6] set];
618     _drawFrameInRect(rect);
619     _drawKnobInRect(knobRect);
620
621     // Draw shadow
622     [[[NSColor blackColor] colorWithAlphaComponent:0.1] set];
623     rect.origin.x++;
624     rect.origin.y++;
625     knobRect.origin.x++;
626     knobRect.origin.y++;
627     _drawFrameInRect(rect);
628     _drawKnobInRect(knobRect);
629 }
630
631 @end
632
633 /*****************************************************************************
634  * TimeLineSlider
635  *****************************************************************************/
636
637 @implementation TimeLineSlider
638
639 - (void)awakeFromNib
640 {
641     if (config_GetInt( VLCIntf, "macosx-interfacestyle" ))
642         o_knob_img = [NSImage imageNamed:@"progression-knob_dark"];
643     else
644         o_knob_img = [NSImage imageNamed:@"progression-knob"];
645     img_rect.size = [o_knob_img size];
646     img_rect.origin.x = img_rect.origin.y = 0;
647 }
648
649 - (void)dealloc
650 {
651     [o_knob_img release];
652     [super dealloc];
653 }
654
655 - (CGFloat)knobPosition
656 {
657     NSRect knobRect = [[self cell] knobRectFlipped:NO];
658     knobRect.origin.x += knobRect.size.width / 2;
659     return knobRect.origin.x;
660 }
661
662 - (void)drawKnobInRect:(NSRect)knobRect
663 {
664     knobRect.origin.x += (knobRect.size.width - img_rect.size.width) / 2;
665     knobRect.size.width = img_rect.size.width;
666     knobRect.size.height = img_rect.size.height;
667     [o_knob_img drawInRect:knobRect fromRect:img_rect operation:NSCompositeSourceOver fraction:1];
668 }
669
670 - (void)drawRect:(NSRect)rect
671 {
672     [(VLCMainWindow *)[self window] drawFancyGradientEffectForTimeSlider];
673     msleep( 10000 ); //wait for the gradient to draw completely
674
675     /* Draw default to make sure the slider behaves correctly */
676     [[NSGraphicsContext currentContext] saveGraphicsState];
677     NSRectClip(NSZeroRect);
678     [super drawRect:rect];
679     [[NSGraphicsContext currentContext] restoreGraphicsState];
680
681     NSRect knobRect = [[self cell] knobRectFlipped:NO];
682     knobRect.origin.y+=1;
683     [self drawKnobInRect: knobRect];
684 }
685
686 @end
687
688 /*****************************************************************************
689  * ITSlider
690  *****************************************************************************/
691
692 @implementation ITSlider
693
694 - (void)awakeFromNib
695 {
696     BOOL b_dark = config_GetInt( VLCIntf, "macosx-interfacestyle" );
697     if (b_dark)
698         img = [NSImage imageNamed:@"volume-slider-knob_dark"];
699     else
700         img = [NSImage imageNamed:@"volume-slider-knob"];
701
702     image_rect.size = [img size];
703     image_rect.origin.x = 0;
704
705     if (b_dark)
706         image_rect.origin.y = -1;
707     else
708         image_rect.origin.y = 0;
709 }
710
711 - (void)drawKnobInRect:(NSRect)knobRect
712 {
713     knobRect.origin.x += (knobRect.size.width - image_rect.size.width) / 2;
714     knobRect.size.width = image_rect.size.width;
715     knobRect.size.height = image_rect.size.height;
716     [img drawInRect:knobRect fromRect:image_rect operation:NSCompositeSourceOver fraction:1];
717 }
718
719 - (void)drawRect:(NSRect)rect
720 {
721     /* Draw default to make sure the slider behaves correctly */
722     [[NSGraphicsContext currentContext] saveGraphicsState];
723     NSRectClip(NSZeroRect);
724     [super drawRect:rect];
725     [[NSGraphicsContext currentContext] restoreGraphicsState];
726
727     NSRect knobRect = [[self cell] knobRectFlipped:NO];
728     knobRect.origin.y+=2;
729     [self drawKnobInRect: knobRect];
730 }
731
732 @end
733
734 /*****************************************************************************
735  * VLCTimeField implementation
736  *****************************************************************************
737  * we need this to catch our click-event in the controller window
738  *****************************************************************************/
739
740 @implementation VLCTimeField
741 + (void)initialize{
742     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
743     NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:@"NO" forKey:@"DisplayTimeAsTimeRemaining"];
744
745     [defaults registerDefaults:appDefaults];
746 }
747
748 - (void)awakeFromNib
749 {
750     NSColor *o_string_color;
751     if (!config_GetInt( VLCIntf, "macosx-interfacestyle"))
752         o_string_color = [NSColor colorWithCalibratedRed:0.229 green:0.229 blue:0.229 alpha:100.0];
753     else
754         o_string_color = [NSColor colorWithCalibratedRed:0.64 green:0.64 blue:0.64 alpha:100.0];
755
756     textAlignment = NSCenterTextAlignment;
757     o_string_attributes_dict = [[NSDictionary dictionaryWithObjectsAndKeys: o_string_color, NSForegroundColorAttributeName, [NSFont titleBarFontOfSize:10.0], NSFontAttributeName, nil] retain];
758 }
759
760 - (void)setAlignment:(NSTextAlignment)alignment
761 {
762     textAlignment = alignment;
763     [self setStringValue:[self stringValue]];
764 }
765
766 - (void)dealloc
767 {
768     [o_string_shadow release];
769     [o_string_attributes_dict release];
770     [super dealloc];
771 }
772
773 - (void)setStringValue:(NSString *)string
774 {
775     if (!o_string_shadow)
776     {
777         o_string_shadow = [[NSShadow alloc] init];
778         [o_string_shadow setShadowColor: [NSColor colorWithCalibratedWhite:1.0 alpha:0.5]];
779         [o_string_shadow setShadowOffset:NSMakeSize(0.0, -1.5)];
780         [o_string_shadow setShadowBlurRadius:0.0];
781     }
782
783     NSMutableAttributedString *o_attributed_string = [[NSMutableAttributedString alloc] initWithString:string attributes: o_string_attributes_dict];
784     NSUInteger i_stringLength = [string length];
785
786     [o_attributed_string addAttribute: NSShadowAttributeName value: o_string_shadow range: NSMakeRange(0, i_stringLength)];
787     [o_attributed_string setAlignment: textAlignment range: NSMakeRange(0, i_stringLength)];
788     [self setAttributedStringValue: o_attributed_string];
789     [o_attributed_string release];
790 }
791
792 - (void)mouseDown: (NSEvent *)ourEvent
793 {
794     if( [ourEvent clickCount] > 1 )
795         [[[VLCMain sharedInstance] controls] goToSpecificTime: nil];
796     else
797     {
798         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayTimeAsTimeRemaining"])
799             [[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@"DisplayTimeAsTimeRemaining"];
800         else
801             [[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"DisplayTimeAsTimeRemaining"];
802     }
803 }
804
805 - (BOOL)timeRemaining
806 {
807     return [[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayTimeAsTimeRemaining"];
808 }
809 @end
810
811 /*****************************************************************************
812  * VLCMainWindowSplitView implementation
813  * comment 1 + 2 taken from NSSplitView.h (10.7 SDK)
814  *****************************************************************************/
815 @implementation VLCMainWindowSplitView : NSSplitView
816 /* Return the color of the dividers that the split view is drawing between subviews. The default implementation of this method returns [NSColor clearColor] for the thick divider style. It will also return [NSColor clearColor] for the thin divider style when the split view is in a textured window. All other thin dividers are drawn with a color that looks good between two white panes. You can override this method to change the color of dividers.
817  */
818 - (NSColor *)dividerColor
819 {
820     return [NSColor colorWithCalibratedRed:.60 green:.60 blue:.60 alpha:1.];
821 }
822
823 /* Return the thickness of the dividers that the split view is drawing between subviews. The default implementation returns a value that depends on the divider style. You can override this method to change the size of dividers.
824  */
825 - (CGFloat)dividerThickness
826 {
827     return 1.0;
828 }
829
830 - (void)adjustSubviews
831 {
832     NSArray *o_subviews = [self subviews];
833     NSRect viewDimensions = [self frame];
834     NSRect leftViewDimensions = [[o_subviews objectAtIndex:0] frame];
835     NSRect rightViewDimensions = [[o_subviews objectAtIndex:1] frame];
836     CGFloat f_dividerThickness = [self dividerThickness];
837
838     leftViewDimensions.size.height = viewDimensions.size.height;
839     [[o_subviews objectAtIndex:0] setFrame: leftViewDimensions];
840
841     rightViewDimensions.origin.x = leftViewDimensions.size.width + f_dividerThickness;
842     rightViewDimensions.size.width = viewDimensions.size.width - leftViewDimensions.size.width - f_dividerThickness;
843     rightViewDimensions.size.height = viewDimensions.size.height;
844     [[o_subviews objectAtIndex:1] setFrame: rightViewDimensions];
845 }
846 @end
847
848 /*****************************************************************************
849  * VLCThreePartImageView interface
850  *****************************************************************************/
851 @implementation VLCThreePartImageView
852 - (void)dealloc
853 {
854     [o_left_img release];
855     [o_middle_img release];
856     [o_right_img release];
857
858     [super dealloc];
859 }
860
861 - (void)setImagesLeft:(NSImage *)left middle: (NSImage *)middle right:(NSImage *)right
862 {
863     if (o_left_img)
864         [o_left_img release];
865     if (o_middle_img)
866         [o_middle_img release];
867     if (o_right_img)
868         [o_right_img release];
869
870     o_left_img = [left retain];
871     o_middle_img = [middle retain];
872     o_right_img = [right retain];
873 }
874
875 - (void)drawRect:(NSRect)rect
876 {
877     NSRect bnds = [self bounds];
878     NSDrawThreePartImage( bnds, o_left_img, o_middle_img, o_right_img, NO, NSCompositeSourceOver, 1, NO );
879 }
880
881 @end
882
883 @implementation VLCThreePartDropView
884
885 - (BOOL)mouseDownCanMoveWindow
886 {
887     return YES;
888 }
889
890 - (void)dealloc
891 {
892     [self unregisterDraggedTypes];
893     [super dealloc];
894 }
895
896 - (void)awakeFromNib
897 {
898     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
899                                    NSFilenamesPboardType, nil]];
900 }
901
902 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
903 {
904     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
905         == NSDragOperationGeneric)
906     {
907         return NSDragOperationGeneric;
908     }
909     else
910     {
911         return NSDragOperationNone;
912     }
913 }
914
915 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
916 {
917     return YES;
918 }
919
920 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
921 {
922     NSPasteboard *o_paste = [sender draggingPasteboard];
923     NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
924     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
925     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
926     BOOL b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
927
928     if( o_carried_data )
929     {
930         if ([o_desired_type isEqualToString:NSFilenamesPboardType])
931         {
932             NSArray *o_array = [NSArray array];
933             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
934             NSUInteger count = [o_values count];
935
936             input_thread_t * p_input = pl_CurrentInput( VLCIntf );
937             BOOL b_returned = NO;
938
939             if (count == 1 && p_input)
940             {
941                 b_returned = input_AddSubtitle( p_input, make_URI([[o_values objectAtIndex:0] UTF8String], NULL), true );
942                 vlc_object_release( p_input );
943                 if(!b_returned)
944                     return YES;
945             }
946             else if( p_input )
947                 vlc_object_release( p_input );
948
949             for( NSUInteger i = 0; i < count; i++)
950             {
951                 NSDictionary *o_dic;
952                 char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], NULL);
953                 if( !psz_uri )
954                     continue;
955
956                 o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
957                 free( psz_uri );
958
959                 o_array = [o_array arrayByAddingObject: o_dic];
960             }
961             if( b_autoplay )
962                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
963             else
964                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
965             return YES;
966         }
967     }
968     [self setNeedsDisplay:YES];
969     return YES;
970 }
971
972 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
973 {
974     [self setNeedsDisplay:YES];
975 }
976
977 @end