]> git.sesse.net Git - vlc/blob - modules/gui/macosx/CoreInteraction.m
933b1fe940f44819fed90e720e3ced52a720113a
[vlc] / modules / gui / macosx / CoreInteraction.m
1 /*****************************************************************************
2  * CoreInteraction.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2011-2013 Felix Paul Kühne
5  * $Id$
6  *
7  * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 #import "CoreInteraction.h"
25 #import "intf.h"
26 #import "open.h"
27 #import "playlist.h"
28 #import <math.h>
29 #import <vlc_playlist.h>
30 #import <vlc_input.h>
31 #import <vlc_keys.h>
32 #import <vlc_vout.h>
33 #import <vlc_vout_osd.h>
34 #import <vlc/vlc.h>
35 #import <vlc_strings.h>
36 #import <vlc_url.h>
37
38 @interface VLCMainWindow (Internal)
39 - (void)jumpWithValue:(char *)p_value forward:(BOOL)b_value;
40 @end
41
42 @implementation VLCCoreInteraction
43 static VLCCoreInteraction *_o_sharedInstance = nil;
44
45 + (VLCCoreInteraction *)sharedInstance
46 {
47     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
48 }
49
50 #pragma mark -
51 #pragma mark Initialization
52
53 - (id)init
54 {
55     if (_o_sharedInstance) {
56         [self dealloc];
57         return _o_sharedInstance;
58     } else
59         _o_sharedInstance = [super init];
60
61     return _o_sharedInstance;
62 }
63
64 - (void)dealloc
65 {
66     [[NSNotificationCenter defaultCenter] removeObserver: self];
67     [super dealloc];
68 }
69
70 - (void)awakeFromNib
71 {
72     [[NSNotificationCenter defaultCenter] addObserver: self
73                                              selector: @selector(applicationWillFinishLaunching:)
74                                                  name: NSApplicationWillFinishLaunchingNotification
75                                                object: nil];
76 }
77
78 #pragma mark -
79 #pragma mark Playback Controls
80
81 - (void)play
82 {
83     input_thread_t * p_input;
84     p_input = pl_CurrentInput(VLCIntf);
85     playlist_t * p_playlist = pl_Get(VLCIntf);
86
87     if (p_input) {
88         playlist_Play(p_playlist);
89         vlc_object_release(p_input);
90     } else {
91         bool empty;
92
93         PL_LOCK;
94         empty = playlist_IsEmpty(p_playlist);
95         PL_UNLOCK;
96
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];
99         else
100             [[[VLCMain sharedInstance] playlist] playItem:nil];
101     }
102 }
103
104 - (void)pause
105 {
106     playlist_Pause(pl_Get(VLCIntf));
107 }
108
109 - (void)stop
110 {
111     playlist_Stop(pl_Get(VLCIntf));
112 }
113
114 - (void)faster
115 {
116     var_TriggerCallback(pl_Get(VLCIntf), "rate-faster");
117 }
118
119 - (void)slower
120 {
121     var_TriggerCallback(pl_Get(VLCIntf), "rate-slower");
122 }
123
124 - (void)normalSpeed
125 {
126     var_SetFloat(pl_Get(VLCIntf), "rate", 1.);
127 }
128
129 - (void)toggleRecord
130 {
131     intf_thread_t *p_intf = VLCIntf;
132     if (!p_intf)
133         return;
134
135     input_thread_t * p_input;
136     p_input = pl_CurrentInput(p_intf);
137     if (p_input) {
138         var_ToggleBool(p_input, "record");
139         vlc_object_release(p_input);
140     }
141 }
142
143 - (void)setPlaybackRate:(int)i_value
144 {
145     playlist_t * p_playlist = pl_Get(VLCIntf);
146
147     double speed = pow(2, (double)i_value / 17);
148     int rate = INPUT_RATE_DEFAULT / speed;
149     if (i_currentPlaybackRate != rate)
150         var_SetFloat(p_playlist, "rate", (float)INPUT_RATE_DEFAULT / (float)rate);
151     i_currentPlaybackRate = rate;
152 }
153
154 - (int)playbackRate
155 {
156     float f_rate;
157
158     intf_thread_t *p_intf = VLCIntf;
159     if (!p_intf)
160         return 0;
161
162     input_thread_t * p_input;
163     p_input = pl_CurrentInput(p_intf);
164     if (p_input) {
165         f_rate = var_GetFloat(p_input, "rate");
166         vlc_object_release(p_input);
167     }
168     else
169     {
170         playlist_t * p_playlist = pl_Get(VLCIntf);
171         f_rate = var_GetFloat(p_playlist, "rate");
172     }
173
174     double value = 17 * log(f_rate) / log(2.);
175     int returnValue = (int) ((value > 0) ? value + .5 : value - .5);
176
177     if (returnValue < -34)
178         returnValue = -34;
179     else if (returnValue > 34)
180         returnValue = 34;
181
182     i_currentPlaybackRate = returnValue;
183     return returnValue;
184 }
185
186 - (void)previous
187 {
188     playlist_Prev(pl_Get(VLCIntf));
189 }
190
191 - (void)next
192 {
193     playlist_Next(pl_Get(VLCIntf));
194 }
195
196 - (int)durationOfCurrentPlaylistItem
197 {
198     intf_thread_t *p_intf = VLCIntf;
199     if (!p_intf)
200         return 0;
201
202     input_thread_t * p_input = pl_CurrentInput(p_intf);
203     int64_t i_duration = -1;
204     if (!p_input)
205         return i_duration;
206
207     input_Control(p_input, INPUT_GET_LENGTH, &i_duration);
208     vlc_object_release(p_input);
209
210     return (int)(i_duration / 1000000);
211 }
212
213 - (NSURL*)URLOfCurrentPlaylistItem
214 {
215     intf_thread_t *p_intf = VLCIntf;
216     if (!p_intf)
217         return nil;
218
219     input_thread_t *p_input = pl_CurrentInput(p_intf);
220     if (!p_input)
221         return nil;
222
223     input_item_t *p_item = input_GetItem(p_input);
224     if (!p_item) {
225         vlc_object_release(p_input);
226         return nil;
227     }
228
229     char *psz_uri = input_item_GetURI(p_item);
230     if (!psz_uri) {
231         vlc_object_release(p_input);
232         return nil;
233     }
234
235     NSURL *o_url;
236     o_url = [NSURL URLWithString:[NSString stringWithUTF8String:psz_uri]];
237     vlc_object_release(p_input);
238
239     return o_url;
240 }
241
242 - (NSString*)nameOfCurrentPlaylistItem
243 {
244     intf_thread_t *p_intf = VLCIntf;
245     if (!p_intf)
246         return nil;
247
248     input_thread_t *p_input = pl_CurrentInput(p_intf);
249     if (!p_input)
250         return nil;
251
252     input_item_t *p_item = input_GetItem(p_input);
253     if (!p_item) {
254         vlc_object_release(p_input);
255         return nil;
256     }
257
258     char *psz_uri = input_item_GetURI(p_item);
259     if (!psz_uri) {
260         vlc_object_release(p_input);
261         return nil;
262     }
263
264     NSString *o_name;
265     char *format = var_InheritString(VLCIntf, "input-title-format");
266     char *formated = str_format_meta(pl_Get(VLCIntf), format);
267     free(format);
268     o_name = [NSString stringWithUTF8String:formated];
269     free(formated);
270
271     NSURL * o_url = [NSURL URLWithString: [NSString stringWithUTF8String: psz_uri]];
272     free(psz_uri);
273
274     if ([o_name isEqualToString:@""]) {
275         if ([o_url isFileURL])
276             o_name = [[NSFileManager defaultManager] displayNameAtPath: [o_url path]];
277         else
278             o_name = [o_url absoluteString];
279     }
280     vlc_object_release(p_input);
281     return o_name;
282 }
283
284 - (void)forward
285 {
286     //LEGACY SUPPORT
287     [self forwardShort];
288 }
289
290 - (void)backward
291 {
292     //LEGACY SUPPORT
293     [self backwardShort];
294 }
295
296 - (void)jumpWithValue:(char *)p_value forward:(BOOL)b_value
297 {
298     input_thread_t *p_input = pl_CurrentInput(VLCIntf);
299     if (!p_input)
300         return;
301
302     int i_interval = var_InheritInteger( p_input, p_value );
303     if (i_interval > 0) {
304         mtime_t val = CLOCK_FREQ * i_interval;
305         if (!b_value)
306             val = val * -1;
307         var_SetTime( p_input, "time-offset", val );
308     }
309     vlc_object_release(p_input);
310 }
311
312 - (void)forwardExtraShort
313 {
314     [self jumpWithValue:"extrashort-jump-size" forward:YES];
315 }
316
317 - (void)backwardExtraShort
318 {
319     [self jumpWithValue:"extrashort-jump-size" forward:NO];
320 }
321
322 - (void)forwardShort
323 {
324     [self jumpWithValue:"short-jump-size" forward:YES];
325 }
326
327 - (void)backwardShort
328 {
329     [self jumpWithValue:"short-jump-size" forward:NO];
330 }
331
332 - (void)forwardMedium
333 {
334     [self jumpWithValue:"medium-jump-size" forward:YES];
335 }
336
337 - (void)backwardMedium
338 {
339     [self jumpWithValue:"medium-jump-size" forward:NO];
340 }
341
342 - (void)forwardLong
343 {
344     [self jumpWithValue:"long-jump-size" forward:YES];
345 }
346
347 - (void)backwardLong
348 {
349     [self jumpWithValue:"long-jump-size" forward:NO];
350 }
351
352 - (void)shuffle
353 {
354     intf_thread_t *p_intf = VLCIntf;
355     if (!p_intf)
356         return;
357
358     vlc_value_t val;
359     playlist_t * p_playlist = pl_Get(p_intf);
360     vout_thread_t *p_vout = getVout();
361
362     var_Get(p_playlist, "random", &val);
363     val.b_bool = !val.b_bool;
364     var_Set(p_playlist, "random", val);
365     if (val.b_bool) {
366         if (p_vout) {
367             vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Random On"));
368             vlc_object_release(p_vout);
369         }
370         config_PutInt(p_playlist, "random", 1);
371     }
372     else
373     {
374         if (p_vout) {
375             vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Random Off"));
376             vlc_object_release(p_vout);
377         }
378         config_PutInt(p_playlist, "random", 0);
379     }
380 }
381
382 - (void)repeatAll
383 {
384     intf_thread_t *p_intf = VLCIntf;
385     if (!p_intf)
386         return;
387
388     playlist_t * p_playlist = pl_Get(p_intf);
389
390     var_SetBool(p_playlist, "repeat", NO);
391     var_SetBool(p_playlist, "loop", YES);
392     config_PutInt(p_playlist, "repeat", NO);
393     config_PutInt(p_playlist, "loop", YES);
394
395     vout_thread_t *p_vout = getVout();
396     if (p_vout) {
397         vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat All"));
398         vlc_object_release(p_vout);
399     }
400 }
401
402 - (void)repeatOne
403 {
404     intf_thread_t *p_intf = VLCIntf;
405     if (!p_intf)
406         return;
407
408     playlist_t * p_playlist = pl_Get(p_intf);
409
410     var_SetBool(p_playlist, "repeat", YES);
411     var_SetBool(p_playlist, "loop", NO);
412     config_PutInt(p_playlist, "repeat", YES);
413     config_PutInt(p_playlist, "loop", NO);
414
415     vout_thread_t *p_vout = getVout();
416     if (p_vout) {
417         vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat One"));
418         vlc_object_release(p_vout);
419     }
420 }
421
422 - (void)repeatOff
423 {
424     intf_thread_t *p_intf = VLCIntf;
425     if (!p_intf)
426         return;
427
428     playlist_t * p_playlist = pl_Get(p_intf);
429
430     var_SetBool(p_playlist, "repeat", NO);
431     var_SetBool(p_playlist, "loop", NO);
432     config_PutInt(p_playlist, "repeat", NO);
433     config_PutInt(p_playlist, "loop", NO);
434
435     vout_thread_t *p_vout = getVout();
436     if (p_vout) {
437         vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat Off"));
438         vlc_object_release(p_vout);
439     }
440 }
441
442 - (void)setAtoB
443 {
444     if (!timeA) {
445         input_thread_t * p_input = pl_CurrentInput(VLCIntf);
446         if (p_input) {
447             timeA = var_GetTime(p_input, "time");
448             vlc_object_release(p_input);
449         }
450     } else if (!timeB) {
451         input_thread_t * p_input = pl_CurrentInput(VLCIntf);
452         if (p_input) {
453             timeB = var_GetTime(p_input, "time");
454             vlc_object_release(p_input);
455         }
456     } else
457         [self resetAtoB];
458 }
459
460 - (void)resetAtoB
461 {
462     timeA = 0;
463     timeB = 0;
464 }
465
466 - (void)updateAtoB
467 {
468     if (timeB) {
469         input_thread_t * p_input = pl_CurrentInput(VLCIntf);
470         if (p_input) {
471             mtime_t currentTime = var_GetTime(p_input, "time");
472             if ( currentTime >= timeB || currentTime < timeA)
473                 var_SetTime(p_input, "time", timeA);
474             vlc_object_release(p_input);
475         }
476     }
477 }
478
479 - (void)volumeUp
480 {
481     intf_thread_t *p_intf = VLCIntf;
482     if (!p_intf)
483         return;
484
485     playlist_VolumeUp(pl_Get(p_intf), 1, NULL);
486 }
487
488 - (void)volumeDown
489 {
490     intf_thread_t *p_intf = VLCIntf;
491     if (!p_intf)
492         return;
493
494     playlist_VolumeDown(pl_Get(p_intf), 1, NULL);
495 }
496
497 - (void)toggleMute
498 {
499     intf_thread_t *p_intf = VLCIntf;
500     if (!p_intf)
501         return;
502
503     playlist_MuteToggle(pl_Get(p_intf));
504 }
505
506 - (void)setMute:(BOOL)b_value
507 {
508     intf_thread_t *p_intf = VLCIntf;
509     if (!p_intf)
510         return;
511
512     playlist_MuteSet(pl_Get(p_intf), b_value);
513 }
514
515 - (BOOL)mute
516 {
517     intf_thread_t *p_intf = VLCIntf;
518     if (!p_intf)
519         return NO;
520
521     BOOL b_is_muted = NO;
522     b_is_muted = playlist_MuteGet(pl_Get(p_intf)) > 0;
523
524     return b_is_muted;
525 }
526
527 - (int)volume
528 {
529     intf_thread_t *p_intf = VLCIntf;
530     if (!p_intf)
531         return 0;
532
533     float volume = playlist_VolumeGet(pl_Get(p_intf));
534
535     return lroundf(volume * AOUT_VOLUME_DEFAULT);
536 }
537
538 - (void)setVolume: (int)i_value
539 {
540     intf_thread_t *p_intf = VLCIntf;
541     if (!p_intf)
542         return;
543
544     float f_value = i_value / (float)AOUT_VOLUME_DEFAULT;
545
546     playlist_VolumeSet(pl_Get(p_intf), f_value);
547 }
548
549 #pragma mark -
550 #pragma mark drag and drop support for VLCVoutView, VLBrushedMetalImageView and VLCThreePartDropView
551 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
552 {
553     NSPasteboard *o_paste = [sender draggingPasteboard];
554     NSArray *o_types = [NSArray arrayWithObject: NSFilenamesPboardType];
555     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
556     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
557     BOOL b_autoplay = config_GetInt(VLCIntf, "macosx-autoplay");
558
559     if (o_carried_data) {
560         if ([o_desired_type isEqualToString:NSFilenamesPboardType]) {
561             NSArray *o_array = [NSArray array];
562             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
563             NSUInteger count = [o_values count];
564
565             input_thread_t * p_input = pl_CurrentInput(VLCIntf);
566             BOOL b_returned = NO;
567
568             if (count == 1 && p_input) {
569                 b_returned = input_AddSubtitle(p_input, vlc_path2uri([[o_values objectAtIndex:0] UTF8String], NULL), true);
570                 vlc_object_release(p_input);
571                 if (!b_returned)
572                     return YES;
573             }
574             else if (p_input)
575                 vlc_object_release(p_input);
576
577             for (NSUInteger i = 0; i < count; i++) {
578                 NSDictionary *o_dic;
579                 char *psz_uri = vlc_path2uri([[o_values objectAtIndex:i] UTF8String], NULL);
580                 if (!psz_uri)
581                     continue;
582
583                 o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
584                 free(psz_uri);
585
586                 o_array = [o_array arrayByAddingObject: o_dic];
587             }
588             if (b_autoplay)
589                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
590             else
591                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
592
593             return YES;
594         }
595     }
596     return NO;
597 }
598
599 #pragma mark -
600 #pragma mark video output stuff
601
602 - (void)setAspectRatioIsLocked:(BOOL)b_value
603 {
604     config_PutInt(VLCIntf, "macosx-lock-aspect-ratio", b_value);
605 }
606
607 - (BOOL)aspectRatioIsLocked
608 {
609     return config_GetInt(VLCIntf, "macosx-lock-aspect-ratio");
610 }
611
612 - (void)toggleFullscreen
613 {
614     intf_thread_t *p_intf = VLCIntf;
615     if (!p_intf)
616         return;
617
618     vout_thread_t *p_vout = getVoutForActiveWindow();
619     if (p_vout) {
620         BOOL b_fs = var_ToggleBool(p_vout, "fullscreen");
621         var_SetBool(pl_Get(p_intf), "fullscreen", b_fs);
622         vlc_object_release(p_vout);
623     } else { // e.g. lion fullscreen toggle
624         BOOL b_fs = var_ToggleBool(pl_Get(p_intf), "fullscreen");
625         [[VLCMain sharedInstance] setFullscreen:b_fs forWindow:nil];
626     }
627 }
628
629 #pragma mark -
630 #pragma mark uncommon stuff
631
632 - (BOOL)fixPreferences
633 {
634     NSMutableString * o_workString;
635     NSRange returnedRange;
636     NSRange fullRange;
637     BOOL b_needsRestart = NO;
638
639     #define fixpref(pref) \
640     o_workString = [[NSMutableString alloc] initWithFormat:@"%s", config_GetPsz(VLCIntf, pref)]; \
641     if ([o_workString length] > 0) \
642     { \
643         returnedRange = [o_workString rangeOfString:@"macosx" options: NSCaseInsensitiveSearch]; \
644         if (returnedRange.location != NSNotFound) \
645         { \
646             if ([o_workString isEqualToString:@"macosx"]) \
647                 [o_workString setString:@""]; \
648             fullRange = NSMakeRange(0, [o_workString length]); \
649             [o_workString replaceOccurrencesOfString:@":macosx" withString:@"" options: NSCaseInsensitiveSearch range: fullRange]; \
650             fullRange = NSMakeRange(0, [o_workString length]); \
651             [o_workString replaceOccurrencesOfString:@"macosx:" withString:@"" options: NSCaseInsensitiveSearch range: fullRange]; \
652             \
653             config_PutPsz(VLCIntf, pref, [o_workString UTF8String]); \
654             b_needsRestart = YES; \
655         } \
656     } \
657     [o_workString release]
658
659     fixpref("control");
660     fixpref("extraintf");
661     #undef fixpref
662
663     return b_needsRestart;
664 }
665
666 @end