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