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