1 /*****************************************************************************
2 * CoreInteraction.m: MacOS X interface module
3 *****************************************************************************
4 * Copyright (C) 2011-2012 Felix Paul Kühne
7 * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #import "CoreInteraction.h"
29 #import <vlc_playlist.h>
34 #import <vlc_strings.h>
37 @implementation VLCCoreInteraction
38 static VLCCoreInteraction *_o_sharedInstance = nil;
40 + (VLCCoreInteraction *)sharedInstance
42 return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
46 #pragma mark Initialization
50 if (_o_sharedInstance) {
52 return _o_sharedInstance;
54 _o_sharedInstance = [super init];
56 return _o_sharedInstance;
61 [[NSNotificationCenter defaultCenter] removeObserver: self];
67 [[NSNotificationCenter defaultCenter] addObserver: self
68 selector: @selector(applicationWillFinishLaunching:)
69 name: NSApplicationWillFinishLaunchingNotification
74 #pragma mark Playback Controls
78 input_thread_t * p_input;
79 p_input = pl_CurrentInput(VLCIntf);
81 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_PLAY_PAUSE);
82 vlc_object_release(p_input);
84 playlist_t * p_playlist = pl_Get(VLCIntf);
88 empty = playlist_IsEmpty(p_playlist);
91 if ([[[VLCMain sharedInstance] playlist] isSelectionEmpty] && ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] == p_playlist->p_local_category || [[[VLCMain sharedInstance] playlist] currentPlaylistRoot] == p_playlist->p_ml_category))
92 [[[VLCMain sharedInstance] open] openFileGeneric];
94 [[[VLCMain sharedInstance] playlist] playItem:nil];
100 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_PAUSE);
105 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_STOP);
110 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_FASTER);
115 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_SLOWER);
120 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_RATE_NORMAL);
125 intf_thread_t *p_intf = VLCIntf;
129 input_thread_t * p_input;
130 p_input = pl_CurrentInput(p_intf);
132 var_ToggleBool(p_input, "record");
133 vlc_object_release(p_input);
137 - (void)setPlaybackRate:(int)i_value
139 playlist_t * p_playlist = pl_Get(VLCIntf);
141 double speed = pow(2, (double)i_value / 17);
142 int rate = INPUT_RATE_DEFAULT / speed;
143 if (i_currentPlaybackRate != rate)
144 var_SetFloat(p_playlist, "rate", (float)INPUT_RATE_DEFAULT / (float)rate);
145 i_currentPlaybackRate = rate;
152 intf_thread_t *p_intf = VLCIntf;
156 input_thread_t * p_input;
157 p_input = pl_CurrentInput(p_intf);
159 f_rate = var_GetFloat(p_input, "rate");
160 vlc_object_release(p_input);
164 playlist_t * p_playlist = pl_Get(VLCIntf);
165 f_rate = var_GetFloat(p_playlist, "rate");
168 double value = 17 * log(f_rate) / log(2.);
169 int returnValue = (int) ((value > 0) ? value + .5 : value - .5);
171 if (returnValue < -34)
173 else if (returnValue > 34)
176 i_currentPlaybackRate = returnValue;
182 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_PREV);
187 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_NEXT);
190 - (int)durationOfCurrentPlaylistItem
192 intf_thread_t *p_intf = VLCIntf;
196 input_thread_t * p_input = pl_CurrentInput(p_intf);
197 int64_t i_duration = -1;
201 input_Control(p_input, INPUT_GET_LENGTH, &i_duration);
202 vlc_object_release(p_input);
204 return (int)(i_duration / 1000000);
207 - (NSURL*)URLOfCurrentPlaylistItem
209 intf_thread_t *p_intf = VLCIntf;
213 input_thread_t *p_input = pl_CurrentInput(p_intf);
217 input_item_t *p_item = input_GetItem(p_input);
219 vlc_object_release(p_input);
223 char *psz_uri = input_item_GetURI(p_item);
225 vlc_object_release(p_input);
230 o_url = [NSURL URLWithString:[NSString stringWithUTF8String:psz_uri]];
231 vlc_object_release(p_input);
236 - (NSString*)nameOfCurrentPlaylistItem
238 intf_thread_t *p_intf = VLCIntf;
242 input_thread_t *p_input = pl_CurrentInput(p_intf);
246 input_item_t *p_item = input_GetItem(p_input);
248 vlc_object_release(p_input);
252 char *psz_uri = input_item_GetURI(p_item);
254 vlc_object_release(p_input);
259 char *format = var_InheritString(VLCIntf, "input-title-format");
260 char *formated = str_format_meta(pl_Get(VLCIntf), format);
262 o_name = [NSString stringWithUTF8String:formated];
265 NSURL * o_url = [NSURL URLWithString: [NSString stringWithUTF8String: psz_uri]];
268 if ([o_name isEqualToString:@""]) {
269 if ([o_url isFileURL])
270 o_name = [[NSFileManager defaultManager] displayNameAtPath: [o_url path]];
272 o_name = [o_url absoluteString];
274 vlc_object_release(p_input);
287 [self backwardShort];
290 - (void)forwardExtraShort
292 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_JUMP_FORWARD_EXTRASHORT);
295 - (void)backwardExtraShort
297 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_JUMP_BACKWARD_EXTRASHORT);
302 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_JUMP_FORWARD_SHORT);
305 - (void)backwardShort
307 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_JUMP_BACKWARD_SHORT);
310 - (void)forwardMedium
312 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_JUMP_FORWARD_MEDIUM);
315 - (void)backwardMedium
317 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_JUMP_BACKWARD_MEDIUM);
322 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_JUMP_FORWARD_LONG);
327 var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_JUMP_BACKWARD_LONG);
332 intf_thread_t *p_intf = VLCIntf;
337 playlist_t * p_playlist = pl_Get(p_intf);
338 vout_thread_t *p_vout = getVout();
340 var_Get(p_playlist, "random", &val);
341 val.b_bool = !val.b_bool;
342 var_Set(p_playlist, "random", val);
345 vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Random On"));
346 vlc_object_release(p_vout);
348 config_PutInt(p_playlist, "random", 1);
353 vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Random Off"));
354 vlc_object_release(p_vout);
356 config_PutInt(p_playlist, "random", 0);
362 intf_thread_t *p_intf = VLCIntf;
366 playlist_t * p_playlist = pl_Get(p_intf);
368 var_SetBool(p_playlist, "repeat", NO);
369 var_SetBool(p_playlist, "loop", YES);
370 config_PutInt(p_playlist, "repeat", NO);
371 config_PutInt(p_playlist, "loop", YES);
373 vout_thread_t *p_vout = getVout();
375 vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat All"));
376 vlc_object_release(p_vout);
382 intf_thread_t *p_intf = VLCIntf;
386 playlist_t * p_playlist = pl_Get(p_intf);
388 var_SetBool(p_playlist, "repeat", YES);
389 var_SetBool(p_playlist, "loop", NO);
390 config_PutInt(p_playlist, "repeat", YES);
391 config_PutInt(p_playlist, "loop", NO);
393 vout_thread_t *p_vout = getVout();
395 vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat One"));
396 vlc_object_release(p_vout);
402 intf_thread_t *p_intf = VLCIntf;
406 playlist_t * p_playlist = pl_Get(p_intf);
408 var_SetBool(p_playlist, "repeat", NO);
409 var_SetBool(p_playlist, "loop", NO);
410 config_PutInt(p_playlist, "repeat", NO);
411 config_PutInt(p_playlist, "loop", NO);
413 vout_thread_t *p_vout = getVout();
415 vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat Off"));
416 vlc_object_release(p_vout);
423 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
425 timeA = var_GetTime(p_input, "time");
426 vlc_object_release(p_input);
429 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
431 timeB = var_GetTime(p_input, "time");
432 vlc_object_release(p_input);
447 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
449 mtime_t currentTime = var_GetTime(p_input, "time");
450 if ( currentTime >= timeB || currentTime < timeA)
451 var_SetTime(p_input, "time", timeA);
452 vlc_object_release(p_input);
459 intf_thread_t *p_intf = VLCIntf;
463 playlist_VolumeUp(pl_Get(p_intf), 1, NULL);
468 intf_thread_t *p_intf = VLCIntf;
472 playlist_VolumeDown(pl_Get(p_intf), 1, NULL);
477 intf_thread_t *p_intf = VLCIntf;
481 playlist_MuteToggle(pl_Get(p_intf));
484 - (void)setMute:(BOOL)b_value
486 intf_thread_t *p_intf = VLCIntf;
490 playlist_MuteSet(pl_Get(p_intf), b_value);
495 intf_thread_t *p_intf = VLCIntf;
499 BOOL b_is_muted = NO;
500 b_is_muted = playlist_MuteGet(pl_Get(p_intf)) > 0;
507 intf_thread_t *p_intf = VLCIntf;
511 float volume = playlist_VolumeGet(pl_Get(p_intf));
513 return lroundf(volume * AOUT_VOLUME_DEFAULT);
516 - (void)setVolume: (int)i_value
518 intf_thread_t *p_intf = VLCIntf;
522 float f_value = i_value / (float)AOUT_VOLUME_DEFAULT;
524 playlist_VolumeSet(pl_Get(p_intf), f_value);
528 #pragma mark drag and drop support for VLCVoutView, VLBrushedMetalImageView and VLCThreePartDropView
529 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
531 NSPasteboard *o_paste = [sender draggingPasteboard];
532 NSArray *o_types = [NSArray arrayWithObject: NSFilenamesPboardType];
533 NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
534 NSData *o_carried_data = [o_paste dataForType:o_desired_type];
535 BOOL b_autoplay = config_GetInt(VLCIntf, "macosx-autoplay");
537 if (o_carried_data) {
538 if ([o_desired_type isEqualToString:NSFilenamesPboardType]) {
539 NSArray *o_array = [NSArray array];
540 NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
541 NSUInteger count = [o_values count];
543 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
544 BOOL b_returned = NO;
546 if (count == 1 && p_input) {
547 b_returned = input_AddSubtitle(p_input, vlc_path2uri([[o_values objectAtIndex:0] UTF8String], NULL), true);
548 vlc_object_release(p_input);
553 vlc_object_release(p_input);
555 for (NSUInteger i = 0; i < count; i++) {
557 char *psz_uri = vlc_path2uri([[o_values objectAtIndex:i] UTF8String], NULL);
561 o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
564 o_array = [o_array arrayByAddingObject: o_dic];
567 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
569 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
578 #pragma mark video output stuff
580 - (void)setAspectRatioIsLocked:(BOOL)b_value
582 config_PutInt(VLCIntf, "macosx-lock-aspect-ratio", b_value);
585 - (BOOL)aspectRatioIsLocked
587 return config_GetInt(VLCIntf, "macosx-lock-aspect-ratio");
590 - (void)toggleFullscreen
592 intf_thread_t *p_intf = VLCIntf;
596 BOOL b_fs = var_ToggleBool(pl_Get(p_intf), "fullscreen");
598 vout_thread_t *p_vout = getVoutForActiveWindow();
600 var_SetBool(p_vout, "fullscreen", b_fs);
601 vlc_object_release(p_vout);
602 } else { // e.g. lion fullscreen toggle
603 [[VLCMain sharedInstance] setFullscreen:b_fs forWindow:nil];
608 #pragma mark uncommon stuff
610 - (BOOL)fixPreferences
612 NSMutableString * o_workString;
613 NSRange returnedRange;
615 BOOL b_needsRestart = NO;
617 #define fixpref(pref) \
618 o_workString = [[NSMutableString alloc] initWithFormat:@"%s", config_GetPsz(VLCIntf, pref)]; \
619 if ([o_workString length] > 0) \
621 returnedRange = [o_workString rangeOfString:@"macosx" options: NSCaseInsensitiveSearch]; \
622 if (returnedRange.location != NSNotFound) \
624 if ([o_workString isEqualToString:@"macosx"]) \
625 [o_workString setString:@""]; \
626 fullRange = NSMakeRange(0, [o_workString length]); \
627 [o_workString replaceOccurrencesOfString:@":macosx" withString:@"" options: NSCaseInsensitiveSearch range: fullRange]; \
628 fullRange = NSMakeRange(0, [o_workString length]); \
629 [o_workString replaceOccurrencesOfString:@"macosx:" withString:@"" options: NSCaseInsensitiveSearch range: fullRange]; \
631 config_PutPsz(VLCIntf, pref, [o_workString UTF8String]); \
632 b_needsRestart = YES; \
635 [o_workString release]
638 fixpref("extraintf");
641 return b_needsRestart;