1 /*****************************************************************************
2 * CoreInteraction.m: MacOS X interface module
3 *****************************************************************************
4 * Copyright (C) 2011-2013 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>
33 #import <vlc_vout_osd.h>
35 #import <vlc_strings.h>
38 @interface VLCMainWindow (Internal)
39 - (void)jumpWithValue:(char *)p_value forward:(BOOL)b_value;
42 @implementation VLCCoreInteraction
43 static VLCCoreInteraction *_o_sharedInstance = nil;
45 + (VLCCoreInteraction *)sharedInstance
47 return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
51 #pragma mark Initialization
55 if (_o_sharedInstance) {
57 return _o_sharedInstance;
59 _o_sharedInstance = [super init];
61 return _o_sharedInstance;
66 [[NSNotificationCenter defaultCenter] removeObserver: self];
72 [[NSNotificationCenter defaultCenter] addObserver: self
73 selector: @selector(applicationWillFinishLaunching:)
74 name: NSApplicationWillFinishLaunchingNotification
79 #pragma mark Playback Controls
83 input_thread_t * p_input;
84 p_input = pl_CurrentInput(VLCIntf);
85 playlist_t * p_playlist = pl_Get(VLCIntf);
88 playlist_Pause(p_playlist);
89 vlc_object_release(p_input);
94 empty = playlist_IsEmpty(p_playlist);
97 if ([[[VLCMain sharedInstance] playlist] isSelectionEmpty] && ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] == p_playlist->p_local_category || [[[VLCMain sharedInstance] playlist] currentPlaylistRoot] == p_playlist->p_ml_category))
98 [[[VLCMain sharedInstance] open] openFileGeneric];
100 [[[VLCMain sharedInstance] playlist] playItem:nil];
106 playlist_t *p_playlist = pl_Get(VLCIntf);
109 bool b_playlist_playing = playlist_Status(p_playlist) == PLAYLIST_RUNNING;
112 if (b_playlist_playing)
113 playlist_Pause(p_playlist);
118 playlist_Stop(pl_Get(VLCIntf));
123 var_TriggerCallback(pl_Get(VLCIntf), "rate-faster");
128 var_TriggerCallback(pl_Get(VLCIntf), "rate-slower");
133 var_SetFloat(pl_Get(VLCIntf), "rate", 1.);
138 intf_thread_t *p_intf = VLCIntf;
142 input_thread_t * p_input;
143 p_input = pl_CurrentInput(p_intf);
145 var_ToggleBool(p_input, "record");
146 vlc_object_release(p_input);
150 - (void)setPlaybackRate:(int)i_value
152 playlist_t * p_playlist = pl_Get(VLCIntf);
154 double speed = pow(2, (double)i_value / 17);
155 int rate = INPUT_RATE_DEFAULT / speed;
156 if (i_currentPlaybackRate != rate)
157 var_SetFloat(p_playlist, "rate", (float)INPUT_RATE_DEFAULT / (float)rate);
158 i_currentPlaybackRate = rate;
165 intf_thread_t *p_intf = VLCIntf;
169 input_thread_t * p_input;
170 p_input = pl_CurrentInput(p_intf);
172 f_rate = var_GetFloat(p_input, "rate");
173 vlc_object_release(p_input);
177 playlist_t * p_playlist = pl_Get(VLCIntf);
178 f_rate = var_GetFloat(p_playlist, "rate");
181 double value = 17 * log(f_rate) / log(2.);
182 int returnValue = (int) ((value > 0) ? value + .5 : value - .5);
184 if (returnValue < -34)
186 else if (returnValue > 34)
189 i_currentPlaybackRate = returnValue;
195 playlist_Prev(pl_Get(VLCIntf));
200 playlist_Next(pl_Get(VLCIntf));
203 - (int)durationOfCurrentPlaylistItem
205 intf_thread_t *p_intf = VLCIntf;
209 input_thread_t * p_input = pl_CurrentInput(p_intf);
210 int64_t i_duration = -1;
214 input_Control(p_input, INPUT_GET_LENGTH, &i_duration);
215 vlc_object_release(p_input);
217 return (int)(i_duration / 1000000);
220 - (NSURL*)URLOfCurrentPlaylistItem
222 intf_thread_t *p_intf = VLCIntf;
226 input_thread_t *p_input = pl_CurrentInput(p_intf);
230 input_item_t *p_item = input_GetItem(p_input);
232 vlc_object_release(p_input);
236 char *psz_uri = input_item_GetURI(p_item);
238 vlc_object_release(p_input);
243 o_url = [NSURL URLWithString:@(psz_uri)];
244 vlc_object_release(p_input);
249 - (NSString*)nameOfCurrentPlaylistItem
251 intf_thread_t *p_intf = VLCIntf;
255 input_thread_t *p_input = pl_CurrentInput(p_intf);
259 input_item_t *p_item = input_GetItem(p_input);
261 vlc_object_release(p_input);
265 char *psz_uri = input_item_GetURI(p_item);
267 vlc_object_release(p_input);
272 char *format = var_InheritString(VLCIntf, "input-title-format");
273 char *formated = str_format_meta(pl_Get(VLCIntf), format);
275 o_name = @(formated);
278 NSURL * o_url = [NSURL URLWithString: @(psz_uri)];
281 if ([o_name isEqualToString:@""]) {
282 if ([o_url isFileURL])
283 o_name = [[NSFileManager defaultManager] displayNameAtPath: [o_url path]];
285 o_name = [o_url absoluteString];
287 vlc_object_release(p_input);
300 [self backwardShort];
303 - (void)jumpWithValue:(char *)p_value forward:(BOOL)b_value
305 input_thread_t *p_input = pl_CurrentInput(VLCIntf);
309 int i_interval = var_InheritInteger( p_input, p_value );
310 if (i_interval > 0) {
311 mtime_t val = CLOCK_FREQ * i_interval;
314 var_SetTime( p_input, "time-offset", val );
316 vlc_object_release(p_input);
319 - (void)forwardExtraShort
321 [self jumpWithValue:"extrashort-jump-size" forward:YES];
324 - (void)backwardExtraShort
326 [self jumpWithValue:"extrashort-jump-size" forward:NO];
331 [self jumpWithValue:"short-jump-size" forward:YES];
334 - (void)backwardShort
336 [self jumpWithValue:"short-jump-size" forward:NO];
339 - (void)forwardMedium
341 [self jumpWithValue:"medium-jump-size" forward:YES];
344 - (void)backwardMedium
346 [self jumpWithValue:"medium-jump-size" forward:NO];
351 [self jumpWithValue:"long-jump-size" forward:YES];
356 [self jumpWithValue:"long-jump-size" forward:NO];
361 intf_thread_t *p_intf = VLCIntf;
366 playlist_t * p_playlist = pl_Get(p_intf);
367 vout_thread_t *p_vout = getVout();
369 var_Get(p_playlist, "random", &val);
370 val.b_bool = !val.b_bool;
371 var_Set(p_playlist, "random", val);
374 vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Random On"));
375 vlc_object_release(p_vout);
377 config_PutInt(p_playlist, "random", 1);
382 vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Random Off"));
383 vlc_object_release(p_vout);
385 config_PutInt(p_playlist, "random", 0);
391 intf_thread_t *p_intf = VLCIntf;
395 playlist_t * p_playlist = pl_Get(p_intf);
397 var_SetBool(p_playlist, "repeat", NO);
398 var_SetBool(p_playlist, "loop", YES);
399 config_PutInt(p_playlist, "repeat", NO);
400 config_PutInt(p_playlist, "loop", YES);
402 vout_thread_t *p_vout = getVout();
404 vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat All"));
405 vlc_object_release(p_vout);
411 intf_thread_t *p_intf = VLCIntf;
415 playlist_t * p_playlist = pl_Get(p_intf);
417 var_SetBool(p_playlist, "repeat", YES);
418 var_SetBool(p_playlist, "loop", NO);
419 config_PutInt(p_playlist, "repeat", YES);
420 config_PutInt(p_playlist, "loop", NO);
422 vout_thread_t *p_vout = getVout();
424 vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat One"));
425 vlc_object_release(p_vout);
431 intf_thread_t *p_intf = VLCIntf;
435 playlist_t * p_playlist = pl_Get(p_intf);
437 var_SetBool(p_playlist, "repeat", NO);
438 var_SetBool(p_playlist, "loop", NO);
439 config_PutInt(p_playlist, "repeat", NO);
440 config_PutInt(p_playlist, "loop", NO);
442 vout_thread_t *p_vout = getVout();
444 vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat Off"));
445 vlc_object_release(p_vout);
452 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
454 timeA = var_GetTime(p_input, "time");
455 vlc_object_release(p_input);
458 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
460 timeB = var_GetTime(p_input, "time");
461 vlc_object_release(p_input);
476 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
478 mtime_t currentTime = var_GetTime(p_input, "time");
479 if ( currentTime >= timeB || currentTime < timeA)
480 var_SetTime(p_input, "time", timeA);
481 vlc_object_release(p_input);
488 intf_thread_t *p_intf = VLCIntf;
492 playlist_VolumeUp(pl_Get(p_intf), 1, NULL);
497 intf_thread_t *p_intf = VLCIntf;
501 playlist_VolumeDown(pl_Get(p_intf), 1, NULL);
506 intf_thread_t *p_intf = VLCIntf;
510 playlist_MuteToggle(pl_Get(p_intf));
513 - (void)setMute:(BOOL)b_value
515 intf_thread_t *p_intf = VLCIntf;
519 playlist_MuteSet(pl_Get(p_intf), b_value);
524 intf_thread_t *p_intf = VLCIntf;
528 BOOL b_is_muted = NO;
529 b_is_muted = playlist_MuteGet(pl_Get(p_intf)) > 0;
536 intf_thread_t *p_intf = VLCIntf;
540 float volume = playlist_VolumeGet(pl_Get(p_intf));
542 return lroundf(volume * AOUT_VOLUME_DEFAULT);
545 - (void)setVolume: (int)i_value
547 intf_thread_t *p_intf = VLCIntf;
551 if (i_value >= self.maxVolume)
552 i_value = self.maxVolume;
554 float f_value = i_value / (float)AOUT_VOLUME_DEFAULT;
556 playlist_VolumeSet(pl_Get(p_intf), f_value);
561 return 1.2 * AOUT_VOLUME_DEFAULT;
565 #pragma mark drag and drop support for VLCVoutView, VLBrushedMetalImageView and VLCThreePartDropView
566 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
568 NSPasteboard *o_paste = [sender draggingPasteboard];
569 NSArray *o_types = @[NSFilenamesPboardType];
570 NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
571 NSData *o_carried_data = [o_paste dataForType:o_desired_type];
572 BOOL b_autoplay = config_GetInt(VLCIntf, "macosx-autoplay");
574 if (o_carried_data) {
575 if ([o_desired_type isEqualToString:NSFilenamesPboardType]) {
576 NSArray *o_array = [NSArray array];
577 NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
578 NSUInteger count = [o_values count];
580 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
581 BOOL b_returned = NO;
583 if (count == 1 && p_input) {
584 b_returned = input_AddSubtitle(p_input, [[o_values objectAtIndex:0] UTF8String], true);
585 vlc_object_release(p_input);
590 vlc_object_release(p_input);
592 for (NSUInteger i = 0; i < count; i++) {
594 char *psz_uri = vlc_path2uri([[o_values objectAtIndex:i] UTF8String], NULL);
598 o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
601 o_array = [o_array arrayByAddingObject: o_dic];
604 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
606 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
615 #pragma mark video output stuff
617 - (void)setAspectRatioIsLocked:(BOOL)b_value
619 config_PutInt(VLCIntf, "macosx-lock-aspect-ratio", b_value);
622 - (BOOL)aspectRatioIsLocked
624 return config_GetInt(VLCIntf, "macosx-lock-aspect-ratio");
627 - (void)toggleFullscreen
629 intf_thread_t *p_intf = VLCIntf;
633 vout_thread_t *p_vout = getVoutForActiveWindow();
635 BOOL b_fs = var_ToggleBool(p_vout, "fullscreen");
636 var_SetBool(pl_Get(p_intf), "fullscreen", b_fs);
637 vlc_object_release(p_vout);
638 } else { // e.g. lion fullscreen toggle
639 BOOL b_fs = var_ToggleBool(pl_Get(p_intf), "fullscreen");
640 [[[VLCMain sharedInstance] voutController] setFullscreen:b_fs forWindow:nil];
645 #pragma mark uncommon stuff
647 - (BOOL)fixPreferences
649 NSMutableString * o_workString;
650 NSRange returnedRange;
652 BOOL b_needsRestart = NO;
654 #define fixpref(pref) \
655 o_workString = [[NSMutableString alloc] initWithFormat:@"%s", config_GetPsz(VLCIntf, pref)]; \
656 if ([o_workString length] > 0) \
658 returnedRange = [o_workString rangeOfString:@"macosx" options: NSCaseInsensitiveSearch]; \
659 if (returnedRange.location != NSNotFound) \
661 if ([o_workString isEqualToString:@"macosx"]) \
662 [o_workString setString:@""]; \
663 fullRange = NSMakeRange(0, [o_workString length]); \
664 [o_workString replaceOccurrencesOfString:@":macosx" withString:@"" options: NSCaseInsensitiveSearch range: fullRange]; \
665 fullRange = NSMakeRange(0, [o_workString length]); \
666 [o_workString replaceOccurrencesOfString:@"macosx:" withString:@"" options: NSCaseInsensitiveSearch range: fullRange]; \
668 config_PutPsz(VLCIntf, pref, [o_workString UTF8String]); \
669 b_needsRestart = YES; \
672 [o_workString release]
675 fixpref("extraintf");
678 return b_needsRestart;