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