From 7ab1d4b0cfd89d052217c852581afa01822b837f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Paul=20K=C3=BChne?= <felix@feepk.net> Date: Thu, 11 Apr 2019 19:22:36 +0200 Subject: [PATCH] macosx: refactor input manager remnants --- .../macosx/VLC.xcodeproj/project.pbxproj | 12 +- modules/gui/macosx/Makefile.am | 4 +- .../coreinteraction/VLCClickerManager.m | 4 +- .../macosx/coreinteraction/VLCInputManager.m | 407 ------------------ modules/gui/macosx/main/VLCMain.h | 2 - modules/gui/macosx/main/VLCMain.m | 16 +- .../VLCPlaybackContinuityController.h} | 25 +- .../VLCPlaybackContinuityController.m | 244 +++++++++++ .../windows/extensions/VLCExtensionsManager.m | 1 + po/POTFILES.in | 4 +- 10 files changed, 266 insertions(+), 453 deletions(-) delete mode 100644 modules/gui/macosx/coreinteraction/VLCInputManager.m rename modules/gui/macosx/{coreinteraction/VLCInputManager.h => playlist/VLCPlaybackContinuityController.h} (74%) create mode 100644 modules/gui/macosx/playlist/VLCPlaybackContinuityController.m diff --git a/extras/package/macosx/VLC.xcodeproj/project.pbxproj b/extras/package/macosx/VLC.xcodeproj/project.pbxproj index 623d90e72d0c..3912b982e0b5 100644 --- a/extras/package/macosx/VLC.xcodeproj/project.pbxproj +++ b/extras/package/macosx/VLC.xcodeproj/project.pbxproj @@ -26,7 +26,7 @@ 1C3113AD1E508C6900D4DD76 /* VLCExtensionsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5CCED71314C0D4A90057F8D1 /* VLCExtensionsManager.m */; }; 1C3113AF1E508C6900D4DD76 /* VLCFSPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BCB590A1DA247CD009BCA66 /* VLCFSPanelController.m */; }; 1C3113B11E508C6900D4DD76 /* VLCFSPanelDraggableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CAEBC001E1EC0A400A99E49 /* VLCFSPanelDraggableView.m */; }; - 1C3113B41E508C6900D4DD76 /* VLCInputManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF812EE1B555A340052293C /* VLCInputManager.m */; }; + 1C3113B41E508C6900D4DD76 /* VLCPlaybackContinuityController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF812EE1B555A340052293C /* VLCPlaybackContinuityController.m */; }; 1C3113B61E508C6900D4DD76 /* VLCMain+OldPrefs.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D871D381B5E6844000B56C0 /* VLCMain+OldPrefs.m */; }; 1C3113B81E508C6900D4DD76 /* VLCMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 8ED6C27D03E2EB1C0059A3A7 /* VLCMain.m */; }; 1C3113BA1E508C6900D4DD76 /* VLCApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D5678EC1D5BA1DC002698F3 /* VLCApplication.m */; }; @@ -533,8 +533,8 @@ 7DE9C7DC220728420089108F /* VLCPlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCPlayerController.m; sourceTree = "<group>"; }; 7DF0435E1972E26A0022B534 /* VLCAddonListItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCAddonListItem.h; sourceTree = "<group>"; }; 7DF0435F1972E26A0022B534 /* VLCAddonListItem.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCAddonListItem.m; sourceTree = "<group>"; }; - 7DF812ED1B555A340052293C /* VLCInputManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCInputManager.h; sourceTree = "<group>"; }; - 7DF812EE1B555A340052293C /* VLCInputManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCInputManager.m; sourceTree = "<group>"; }; + 7DF812ED1B555A340052293C /* VLCPlaybackContinuityController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCPlaybackContinuityController.h; sourceTree = "<group>"; }; + 7DF812EE1B555A340052293C /* VLCPlaybackContinuityController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCPlaybackContinuityController.m; sourceTree = "<group>"; }; 7DF812EF1B555C8E0052293C /* VLCKeyboardBacklightControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCKeyboardBacklightControl.h; sourceTree = "<group>"; }; 7DF812F01B555C8E0052293C /* VLCKeyboardBacklightControl.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCKeyboardBacklightControl.m; sourceTree = "<group>"; }; 8E49720006417F6800370C9F /* VLCInformationWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCInformationWindowController.h; sourceTree = "<group>"; }; @@ -854,8 +854,6 @@ 7D66D4352200BC340040D04A /* VLCClickerManager.m */, CC448A6013B68A0B009F72E0 /* VLCCoreInteraction.h */, CC448A6113B68A0B009F72E0 /* VLCCoreInteraction.m */, - 7DF812ED1B555A340052293C /* VLCInputManager.h */, - 7DF812EE1B555A340052293C /* VLCInputManager.m */, 7D66D4372200C5B80040D04A /* VLCVideoFilterHelper.h */, 7D66D4382200C5B80040D04A /* VLCVideoFilterHelper.m */, ); @@ -965,6 +963,8 @@ 1C1ED5142205A96600811EC0 /* playlist */ = { isa = PBXGroup; children = ( + 7DF812ED1B555A340052293C /* VLCPlaybackContinuityController.h */, + 7DF812EE1B555A340052293C /* VLCPlaybackContinuityController.m */, 7DE9C7DB220728420089108F /* VLCPlayerController.h */, 7DE9C7DC220728420089108F /* VLCPlayerController.m */, 7D445D7F2202524000263D34 /* VLCPlaylistController.h */, @@ -1643,7 +1643,7 @@ 1C3113AF1E508C6900D4DD76 /* VLCFSPanelController.m in Sources */, 7D66D4362200BC340040D04A /* VLCClickerManager.m in Sources */, 1C3113B11E508C6900D4DD76 /* VLCFSPanelDraggableView.m in Sources */, - 1C3113B41E508C6900D4DD76 /* VLCInputManager.m in Sources */, + 1C3113B41E508C6900D4DD76 /* VLCPlaybackContinuityController.m in Sources */, 1C3113B61E508C6900D4DD76 /* VLCMain+OldPrefs.m in Sources */, 1C3113B81E508C6900D4DD76 /* VLCMain.m in Sources */, 1CAC3EE820CD1B3B00613DB2 /* VLCVideoOutputProvider.m in Sources */, diff --git a/modules/gui/macosx/Makefile.am b/modules/gui/macosx/Makefile.am index b250880b5a72..4aa0319f5730 100644 --- a/modules/gui/macosx/Makefile.am +++ b/modules/gui/macosx/Makefile.am @@ -30,8 +30,6 @@ libmacosx_plugin_la_SOURCES = \ gui/macosx/coreinteraction/VLCClickerManager.m \ gui/macosx/coreinteraction/VLCCoreInteraction.h \ gui/macosx/coreinteraction/VLCCoreInteraction.m \ - gui/macosx/coreinteraction/VLCInputManager.h \ - gui/macosx/coreinteraction/VLCInputManager.m \ gui/macosx/coreinteraction/VLCVideoFilterHelper.h \ gui/macosx/coreinteraction/VLCVideoFilterHelper.m \ gui/macosx/extensions/NSScreen+VLCAdditions.h \ @@ -118,6 +116,8 @@ libmacosx_plugin_la_SOURCES = \ gui/macosx/panels/dialogs/VLCResumeDialogController.m \ gui/macosx/panels/dialogs/VLCTextfieldPanelController.h \ gui/macosx/panels/dialogs/VLCTextfieldPanelController.m \ + gui/macosx/playlist/VLCPlaybackContinuityController.h \ + gui/macosx/playlist/VLCPlaybackContinuityController.m \ gui/macosx/playlist/VLCPlayerController.h \ gui/macosx/playlist/VLCPlayerController.m \ gui/macosx/playlist/VLCPlaylistController.h \ diff --git a/modules/gui/macosx/coreinteraction/VLCClickerManager.m b/modules/gui/macosx/coreinteraction/VLCClickerManager.m index dade9fa98b37..44611bab8440 100644 --- a/modules/gui/macosx/coreinteraction/VLCClickerManager.m +++ b/modules/gui/macosx/coreinteraction/VLCClickerManager.m @@ -25,7 +25,6 @@ #include <vlc_common.h> #include <vlc_actions.h> -#import "coreinteraction/VLCInputManager.h" #import "coreinteraction/VLCCoreInteraction.h" #import "extensions/NSSound+VLCAdditions.h" #import "imported/SPMediaKeyTap/SPMediaKeyTap.h" @@ -111,8 +110,7 @@ _mediaKeyController = [[SPMediaKeyTap alloc] initWithDelegate:self]; VLCMain *main = [VLCMain sharedInstance]; - if (b_mediaKeySupport && ([[[main playlistController] playlistModel] numberOfPlaylistItems] > 0 || - [[main inputManager] hasInput])) { + if (b_mediaKeySupport && ([[[main playlistController] playlistModel] numberOfPlaylistItems] > 0)) { if (!b_mediaKeyTrapEnabled) { msg_Dbg(p_intf, "Enabling media key support"); if ([_mediaKeyController startWatchingMediaKeys]) { diff --git a/modules/gui/macosx/coreinteraction/VLCInputManager.m b/modules/gui/macosx/coreinteraction/VLCInputManager.m deleted file mode 100644 index 888256044802..000000000000 --- a/modules/gui/macosx/coreinteraction/VLCInputManager.m +++ /dev/null @@ -1,407 +0,0 @@ -/***************************************************************************** - * VLCInputManager.m: MacOS X interface module - ***************************************************************************** - * Copyright (C) 2015-2018 VLC authors and VideoLAN - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. - *****************************************************************************/ - -#import "VLCInputManager.h" - -#include <vlc_url.h> -#import <vlc_playlist_legacy.h> - -#import "coreinteraction/VLCCoreInteraction.h" -#import "main/CompatibilityFixes.h" -#import "main/VLCMain.h" -#import "menus/VLCMainMenu.h" -#import "panels/VLCTrackSynchronizationWindowController.h" -#import "panels/dialogs/VLCResumeDialogController.h" -#import "windows/extensions/VLCExtensionsManager.h" -#import "windows/mainwindow/VLCMainWindow.h" -#import "windows/video/VLCVoutView.h" - -@interface VLCInputManager() -- (void)updateMainMenu; -- (void)updateMainWindow; -@end - -#pragma mark Callbacks - -static int InputThreadChanged(vlc_object_t *p_this, const char *psz_var, - vlc_value_t oldval, vlc_value_t new_val, void *param) -{ - @autoreleasepool { - VLCInputManager *inputManager = (__bridge VLCInputManager *)param; - [inputManager performSelectorOnMainThread:@selector(inputThreadChanged) withObject:nil waitUntilDone:NO]; - } - - return VLC_SUCCESS; -} - -static NSDate *lastPositionUpdate = nil; - -static int InputEvent(vlc_object_t *p_this, const char *psz_var, - vlc_value_t oldval, vlc_value_t new_val, void *param) -{ - @autoreleasepool { - VLCInputManager *inputManager = (__bridge VLCInputManager *)param; - - switch (new_val.i_int) { - case INPUT_EVENT_STATE: - [inputManager performSelectorOnMainThread:@selector(playbackStatusUpdated) withObject: nil waitUntilDone:NO]; - break; - case INPUT_EVENT_RATE: - break; - case INPUT_EVENT_POSITION: - break; - case INPUT_EVENT_TITLE: - case INPUT_EVENT_CHAPTER: - [inputManager performSelectorOnMainThread:@selector(updateMainMenu) withObject: nil waitUntilDone:NO]; - break; - case INPUT_EVENT_CACHE: - [inputManager performSelectorOnMainThread:@selector(updateMainWindow) withObject:nil waitUntilDone:NO]; - break; - case INPUT_EVENT_STATISTICS: - break; - case INPUT_EVENT_ES: - break; - case INPUT_EVENT_VOUT: - break; - case INPUT_EVENT_ITEM_META: - case INPUT_EVENT_ITEM_INFO: - [inputManager performSelectorOnMainThread:@selector(updateMainMenu) withObject: nil waitUntilDone:NO]; - [inputManager performSelectorOnMainThread:@selector(updateName) withObject: nil waitUntilDone:NO]; - break; - case INPUT_EVENT_BOOKMARK: - break; - case INPUT_EVENT_RECORD: - break; - case INPUT_EVENT_PROGRAM: - [inputManager performSelectorOnMainThread:@selector(updateMainMenu) withObject: nil waitUntilDone:NO]; - break; - case INPUT_EVENT_ITEM_EPG: - break; - case INPUT_EVENT_SIGNAL: - break; - - case INPUT_EVENT_DEAD: - [inputManager performSelectorOnMainThread:@selector(updateName) withObject: nil waitUntilDone:NO]; - break; - - default: - break; - } - - return VLC_SUCCESS; - } -} - -#pragma mark - -#pragma mark InputManager implementation - -@interface VLCInputManager() -{ - __weak VLCMain *o_main; - - input_thread_t *p_current_input; - dispatch_queue_t informInputChangedQueue; -} -@end - -@implementation VLCInputManager - -+ (void)initialize -{ - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys: - [NSArray array], @"recentlyPlayedMediaList", - [NSDictionary dictionary], @"recentlyPlayedMedia", nil]; - - [defaults registerDefaults:appDefaults]; -} - -- (id)initWithMain:(VLCMain *)o_mainObj -{ - self = [super init]; - if(self) { - msg_Dbg(getIntf(), "Initializing input manager"); - - o_main = o_mainObj; - var_AddCallback(pl_Get(getIntf()), "input-current", InputThreadChanged, (__bridge void *)self); - - informInputChangedQueue = dispatch_queue_create("org.videolan.vlc.inputChangedQueue", DISPATCH_QUEUE_SERIAL); - } - return self; -} - -/* - * TODO: Investigate if this can be moved to dealloc again. Current problems: - * - dealloc might be never called of this object, as strong references could be in the - * (already stopped) main loop, preventing the refcount to go 0. - * - Calling var_DelCallback waits for all callbacks to finish. Thus, while dealloc is already - * called, callback might grab a reference to this object again, which could cause trouble. - */ -- (void)deinit -{ - msg_Dbg(getIntf(), "Deinitializing input manager"); - - if (p_current_input) { - /* continue playback where you left off */ - [self storePlaybackPositionForItem:p_current_input]; - - var_DelCallback(p_current_input, "intf-event", InputEvent, (__bridge void *)self); - input_Release(p_current_input); - p_current_input = NULL; - } - - var_DelCallback(pl_Get(getIntf()), "input-current", InputThreadChanged, (__bridge void *)self); - -#if !OS_OBJECT_USE_OBJC - dispatch_release(informInputChangedQueue); -#endif -} - -- (void)inputThreadChanged -{ - if (p_current_input) { - var_DelCallback(p_current_input, "intf-event", InputEvent, (__bridge void *)self); - input_Release(p_current_input); - p_current_input = NULL; - - [[o_main mainMenu] setRateControlsEnabled: NO]; - - [[NSNotificationCenter defaultCenter] postNotificationName:VLCInputChangedNotification - object:nil]; - } - - // Cancel pending resume dialogs - [[[VLCMain sharedInstance] resumeDialog] cancel]; - - input_thread_t *p_input_changed = NULL; - - // object is hold here and released then it is dead - p_current_input = playlist_CurrentInput(pl_Get(getIntf())); - if (p_current_input) { - var_AddCallback(p_current_input, "intf-event", InputEvent, (__bridge void *)self); - [self playbackStatusUpdated]; - [[o_main mainMenu] setRateControlsEnabled: YES]; - - if ([o_main activeVideoPlayback] && [[[o_main mainWindow] videoView] isHidden]) { - [[o_main mainWindow] changePlaylistState: psPlaylistItemChangedEvent]; - } - - p_input_changed = input_Hold(p_current_input); - -// [[o_main playlist] currentlyPlayingItemChanged]; - - [self continuePlaybackWhereYouLeftOff:p_current_input]; - - [[NSNotificationCenter defaultCenter] postNotificationName:VLCInputChangedNotification - object:nil]; - } - - [self updateMainWindow]; - [self updateMainMenu]; - - /* - * Due to constraints within NSAttributedString's main loop runtime handling - * and other issues, we need to inform the extension manager on a separate thread. - * The serial queue ensures that changed inputs are propagated in the same order as they arrive. - */ - dispatch_async(informInputChangedQueue, ^{ - [[self->o_main extensionsManager] inputChanged:p_input_changed]; - if (p_input_changed) - input_Release(p_input_changed); - }); -} - -- (void)playbackStatusUpdated -{ - // On shutdown, input might not be dead yet. Cleanup actions like itunes playback - // and playback positon are done in different code paths (dealloc and appWillTerminate:). - if ([[VLCMain sharedInstance] isTerminating]) { - return; - } - - int64_t state = -1; - if (p_current_input) { - state = var_GetInteger(p_current_input, "state"); - } - - if (state != PLAYING_S) { - if (state == END_S || state == -1) { - /* continue playback where you left off */ - if (p_current_input) - [self storePlaybackPositionForItem:p_current_input]; - } - } - - [self updateMainWindow]; -} - -- (void)updateMainWindow -{ - [[o_main mainWindow] updateWindow]; -} - -- (void)updateName -{ - [[o_main mainWindow] updateName]; -} - -- (void)updateMainMenu -{ -} - -- (BOOL)hasInput -{ - return p_current_input != NULL; -} - -#pragma mark - -#pragma mark Resume logic - - -- (BOOL)isValidResumeItem:(input_item_t *)p_item -{ - char *psz_url = input_item_GetURI(p_item); - NSString *urlString = toNSStr(psz_url); - free(psz_url); - - if ([urlString isEqualToString:@""]) - return NO; - - NSURL *url = [NSURL URLWithString:urlString]; - - if (![url isFileURL]) - return NO; - - BOOL isDir = false; - if (![[NSFileManager defaultManager] fileExistsAtPath:[url path] isDirectory:&isDir]) - return NO; - - if (isDir) - return NO; - - return YES; -} - -- (void)continuePlaybackWhereYouLeftOff:(input_thread_t *)p_input_thread -{ - NSDictionary *recentlyPlayedFiles = [[NSUserDefaults standardUserDefaults] objectForKey:@"recentlyPlayedMedia"]; - if (!recentlyPlayedFiles) - return; - - input_item_t *p_item = input_GetItem(p_input_thread); - if (!p_item) - return; - - /* allow the user to over-write the start/stop/run-time */ - if (var_GetFloat(p_input_thread, "run-time") > 0 || - var_GetFloat(p_input_thread, "start-time") > 0 || - var_GetFloat(p_input_thread, "stop-time") != 0) { - return; - } - - /* check for file existance before resuming */ - if (![self isValidResumeItem:p_item]) - return; - - char *psz_url = vlc_uri_decode(input_item_GetURI(p_item)); - if (!psz_url) - return; - NSString *url = toNSStr(psz_url); - free(psz_url); - - NSNumber *lastPosition = [recentlyPlayedFiles objectForKey:url]; - if (!lastPosition || lastPosition.intValue <= 0) - return; - - int settingValue = (int)config_GetInt("macosx-continue-playback"); - if (settingValue == 2) // never resume - return; - - CompletionBlock completionBlock = ^(enum ResumeResult result) { - - if (result == RESUME_RESTART) - return; - - vlc_tick_t lastPos = vlc_tick_from_sec( lastPosition.intValue ); - msg_Dbg(getIntf(), "continuing playback at %lld", lastPos); - var_SetInteger(p_input_thread, "time", lastPos); - }; - - if (settingValue == 1) { // always - completionBlock(RESUME_NOW); - return; - } - - [[[VLCMain sharedInstance] resumeDialog] showWindowWithItem:p_item - withLastPosition:lastPosition.intValue - completionBlock:completionBlock]; - -} - -- (void)storePlaybackPositionForItem:(input_thread_t *)p_input_thread -{ - if (!var_InheritBool(getIntf(), "macosx-recentitems")) - return; - - input_item_t *p_item = input_GetItem(p_input_thread); - if (!p_item) - return; - - if (![self isValidResumeItem:p_item]) - return; - - char *psz_url = vlc_uri_decode(input_item_GetURI(p_item)); - if (!psz_url) - return; - NSString *url = toNSStr(psz_url); - free(psz_url); - - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - NSMutableDictionary *mutDict = [[NSMutableDictionary alloc] initWithDictionary:[defaults objectForKey:@"recentlyPlayedMedia"]]; - - float relativePos = var_GetFloat(p_input_thread, "position"); - long long pos = SEC_FROM_VLC_TICK(var_GetInteger(p_input_thread, "time")); - long long dur = SEC_FROM_VLC_TICK(input_item_GetDuration(p_item)); - - NSMutableArray *mediaList = [[defaults objectForKey:@"recentlyPlayedMediaList"] mutableCopy]; - - if (relativePos > .05 && relativePos < .95 && dur > 180) { - msg_Dbg(getIntf(), "Store current playback position of %f", relativePos); - [mutDict setObject:[NSNumber numberWithInteger:pos] forKey:url]; - - [mediaList removeObject:url]; - [mediaList addObject:url]; - NSUInteger mediaListCount = mediaList.count; - if (mediaListCount > 30) { - for (NSUInteger x = 0; x < mediaListCount - 30; x++) { - [mutDict removeObjectForKey:[mediaList firstObject]]; - [mediaList removeObjectAtIndex:0]; - } - } - } else { - [mutDict removeObjectForKey:url]; - [mediaList removeObject:url]; - } - [defaults setObject:mutDict forKey:@"recentlyPlayedMedia"]; - [defaults setObject:mediaList forKey:@"recentlyPlayedMediaList"]; - [defaults synchronize]; -} - -@end diff --git a/modules/gui/macosx/main/VLCMain.h b/modules/gui/macosx/main/VLCMain.h index 861eaf5fd921..5a7ad20e559a 100644 --- a/modules/gui/macosx/main/VLCMain.h +++ b/modules/gui/macosx/main/VLCMain.h @@ -60,7 +60,6 @@ static NSString * VLCAppleRemoteSettingChangedNotification = @"VLCAppleRemoteSet @class AppleRemote; @class VLCInformationWindowController; @class VLCMainMenu; -@class VLCInputManager; @class VLCResumeDialogController; @class VLCSimplePrefsController; @class VLCPrefs; @@ -96,7 +95,6 @@ static NSString * VLCAppleRemoteSettingChangedNotification = @"VLCAppleRemoteSet - (VLCPrefs *)preferences; - (VLCCoreDialogProvider *)coreDialogProvider; - (VLCResumeDialogController *)resumeDialog; -- (VLCInputManager *)inputManager; - (VLCExtensionsManager *)extensionsManager; - (VLCStatusBarIcon *)statusBarIcon; diff --git a/modules/gui/macosx/main/VLCMain.m b/modules/gui/macosx/main/VLCMain.m index f4d07db9c97e..a1aafe0bbc04 100644 --- a/modules/gui/macosx/main/VLCMain.m +++ b/modules/gui/macosx/main/VLCMain.m @@ -43,7 +43,6 @@ #include <vlc_variables.h> #import "coreinteraction/VLCCoreInteraction.h" -#import "coreinteraction/VLCInputManager.h" #import "library/VLCLibraryWindow.h" @@ -64,6 +63,7 @@ #import "playlist/VLCPlaylistController.h" #import "playlist/VLCPlayerController.h" #import "playlist/VLCPlaylistModel.h" +#import "playlist/VLCPlaybackContinuityController.h" #import "preferences/prefs.h" #import "preferences/VLCSimplePrefsController.h" @@ -178,7 +178,7 @@ static int ShowController(vlc_object_t *p_this, const char *psz_variable, VLCCoreDialogProvider *_coredialogs; VLCBookmarksWindowController *_bookmarks; VLCResumeDialogController *_resume_dialog; - VLCInputManager *_input_manager; + VLCPlaybackContinuityController *_continuityController; VLCLogWindowController *_messagePanelController; VLCStatusBarIcon *_statusBarIcon; VLCTrackSynchronizationWindowController *_trackSyncPanel; @@ -228,7 +228,7 @@ static VLCMain *sharedInstance = nil; [VLCApplication sharedApplication].delegate = self; _playlistController = [[VLCPlaylistController alloc] initWithPlaylist:vlc_intf_GetMainPlaylist(p_intf)]; - _input_manager = [[VLCInputManager alloc] initWithMain:self]; + _continuityController = [[VLCPlaybackContinuityController alloc] init]; // first initalize extensions dialog provider, then core dialog // provider which will register both at the core @@ -331,7 +331,7 @@ static VLCMain *sharedInstance = nil; return; b_intf_terminating = true; - [_input_manager deinit]; + _continuityController = nil; if (notification == nil) [[NSNotificationCenter defaultCenter] postNotificationName: NSApplicationWillTerminateNotification object: nil]; @@ -443,9 +443,6 @@ static VLCMain *sharedInstance = nil; if ([self mainWindow]) { [[self mainWindow] setVideoplayEnabled]; } - - // update sleep blockers - [_input_manager playbackStatusUpdated]; } #pragma mark - @@ -471,11 +468,6 @@ static VLCMain *sharedInstance = nil; return _libraryWindowController; } -- (VLCInputManager *)inputManager -{ - return _input_manager; -} - - (VLCExtensionsManager *)extensionsManager { return _extensionsManager; diff --git a/modules/gui/macosx/coreinteraction/VLCInputManager.h b/modules/gui/macosx/playlist/VLCPlaybackContinuityController.h similarity index 74% rename from modules/gui/macosx/coreinteraction/VLCInputManager.h rename to modules/gui/macosx/playlist/VLCPlaybackContinuityController.h index 47bb1ddaa274..325aa9698d2f 100644 --- a/modules/gui/macosx/coreinteraction/VLCInputManager.h +++ b/modules/gui/macosx/playlist/VLCPlaybackContinuityController.h @@ -1,7 +1,10 @@ /***************************************************************************** - * VLCInputManager.h: MacOS X interface module + * VLCPlaybackContinuityController.h: MacOS X interface module ***************************************************************************** - * Copyright (C) 2015 VLC authors and VideoLAN + * Copyright (C) 2015-2019 VLC authors and VideoLAN + * + * Authors: Felix Paul Kühne <fkuehne # videolan.org> + * David Fuhrmann <dfuhrmann # videolan.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,22 +23,6 @@ #import <Cocoa/Cocoa.h> -#include <vlc_common.h> -#import <vlc_interface.h> - - - -@class VLCMain; - -@interface VLCInputManager : NSObject - -- (id)initWithMain:(VLCMain *)o_mainObj; -- (void)deinit; - -- (void)inputThreadChanged; - -- (void)playbackStatusUpdated; - -- (BOOL)hasInput; +@interface VLCPlaybackContinuityController : NSObject @end diff --git a/modules/gui/macosx/playlist/VLCPlaybackContinuityController.m b/modules/gui/macosx/playlist/VLCPlaybackContinuityController.m new file mode 100644 index 000000000000..d4d319732c32 --- /dev/null +++ b/modules/gui/macosx/playlist/VLCPlaybackContinuityController.m @@ -0,0 +1,244 @@ +/***************************************************************************** + * VLCPlaybackContinuityController.m: MacOS X interface module + ***************************************************************************** + * Copyright (C) 2015-2019 VLC authors and VideoLAN + * + * Authors: Felix Paul Kühne <fkuehne # videolan.org> + * David Fuhrmann <dfuhrmann # videolan.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#import "VLCPlaybackContinuityController.h" + +#import "main/VLCMain.h" +#import "panels/dialogs/VLCResumeDialogController.h" +#import "playlist/VLCPlaylistController.h" +#import "playlist/VLCPlayerController.h" + +#import <vlc_url.h> + +@interface VLCPlaybackContinuityController() +{ + __weak VLCMain *_mainInstance; + input_item_t *p_current_input; +} +@end + +@implementation VLCPlaybackContinuityController + ++ (void)initialize +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys: + [NSArray array], @"recentlyPlayedMediaList", + [NSDictionary dictionary], @"recentlyPlayedMedia", nil]; + + [defaults registerDefaults:appDefaults]; +} + +- (id)init +{ + self = [super init]; + if (self) { + _mainInstance = [VLCMain sharedInstance]; + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(inputItemChanged:) + name:VLCPlaylistCurrentItemChanged + object:nil]; + [notificationCenter addObserver:self + selector:@selector(playbackStatusUpdated:) + name:VLCPlayerStateChanged + object:nil]; + } + return self; +} + +- (void)dealloc +{ + msg_Dbg(getIntf(), "Deinitializing input manager"); + + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + if (p_current_input) { + /* continue playback where you left off */ + [self storePlaybackPositionForItem:p_current_input player:_mainInstance.playlistController.playerController]; + } +} + +- (void)inputItemChanged:(NSNotification *)aNotification +{ + // Cancel pending resume dialogs + [[_mainInstance resumeDialog] cancel]; + + // object is hold here and released then it is dead + p_current_input = [[_mainInstance playlistController] currentlyPlayingInputItem]; + if (p_current_input) { + VLCPlaylistController *playlistController = aNotification.object; + [self continuePlaybackWhereYouLeftOff:p_current_input player:playlistController.playerController]; + } +} + +- (void)playbackStatusUpdated:(NSNotification *)aNotification +{ + // On shutdown, input might not be dead yet. Cleanup actions like itunes playback + // and playback positon are done in different code paths (dealloc and appWillTerminate:). + if ([_mainInstance isTerminating]) { + return; + } + + VLCPlayerController *playerController = aNotification.object; + enum vlc_player_state playerState = [playerController playerState]; + + if (playerState == VLC_PLAYER_STATE_STOPPED || playerState == VLC_PLAYER_STATE_STOPPING) { + /* continue playback where you left off */ + if (p_current_input) + [self storePlaybackPositionForItem:p_current_input player:playerController]; + } +} + +- (BOOL)isValidResumeItem:(input_item_t *)p_item +{ + char *psz_url = input_item_GetURI(p_item); + NSString *urlString = toNSStr(psz_url); + free(psz_url); + + if ([urlString isEqualToString:@""]) + return NO; + + NSURL *url = [NSURL URLWithString:urlString]; + + if (![url isFileURL]) + return NO; + + BOOL isDir = false; + if (![[NSFileManager defaultManager] fileExistsAtPath:[url path] isDirectory:&isDir]) + return NO; + + if (isDir) + return NO; + + return YES; +} + +- (void)continuePlaybackWhereYouLeftOff:(input_item_t *)p_input_item player:(VLCPlayerController *)playerController +{ + NSDictionary *recentlyPlayedFiles = [[NSUserDefaults standardUserDefaults] objectForKey:@"recentlyPlayedMedia"]; + if (!recentlyPlayedFiles) + return; + + if (!p_input_item) + return; + + /* allow the user to over-write the start/stop/run-time */ + // FIXME: reimplement using new playlist +#if 0 + if (var_GetFloat(p_input_thread, "run-time") > 0 || + var_GetFloat(p_input_thread, "start-time") > 0 || + var_GetFloat(p_input_thread, "stop-time") != 0) { + return; + } +#endif + + /* check for file existance before resuming */ + if (![self isValidResumeItem:p_input_item]) + return; + + char *psz_url = vlc_uri_decode(input_item_GetURI(p_input_item)); + if (!psz_url) + return; + NSString *url = toNSStr(psz_url); + free(psz_url); + + NSNumber *lastPosition = [recentlyPlayedFiles objectForKey:url]; + if (!lastPosition || lastPosition.intValue <= 0) + return; + + int settingValue = (int)config_GetInt("macosx-continue-playback"); + if (settingValue == 2) // never resume + return; + + CompletionBlock completionBlock = ^(enum ResumeResult result) { + + if (result == RESUME_RESTART) + return; + + vlc_tick_t lastPos = vlc_tick_from_sec( lastPosition.intValue ); + msg_Dbg(getIntf(), "continuing playback at %lld", lastPos); + + [playerController setTimePrecise: lastPos]; + }; + + if (settingValue == 1) { // always + completionBlock(RESUME_NOW); + return; + } + + [[_mainInstance resumeDialog] showWindowWithItem:p_input_item + withLastPosition:lastPosition.intValue + completionBlock:completionBlock]; + +} + +- (void)storePlaybackPositionForItem:(input_item_t *)p_input_item player:(VLCPlayerController *)playerController +{ + if (!var_InheritBool(getIntf(), "macosx-recentitems")) + return; + + if (!p_input_item) + return; + + if (![self isValidResumeItem:p_input_item]) + return; + + char *psz_url = vlc_uri_decode(input_item_GetURI(p_input_item)); + if (!psz_url) + return; + NSString *url = toNSStr(psz_url); + free(psz_url); + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSMutableDictionary *mutDict = [[NSMutableDictionary alloc] initWithDictionary:[defaults objectForKey:@"recentlyPlayedMedia"]]; + + float relativePos = playerController.position; + long long pos = SEC_FROM_VLC_TICK(playerController.time); + long long dur = SEC_FROM_VLC_TICK(input_item_GetDuration(p_input_item)); + + NSMutableArray *mediaList = [[defaults objectForKey:@"recentlyPlayedMediaList"] mutableCopy]; + + if (relativePos > .05 && relativePos < .95 && dur > 180) { + msg_Dbg(getIntf(), "Store current playback position of %f", relativePos); + [mutDict setObject:[NSNumber numberWithInteger:pos] forKey:url]; + + [mediaList removeObject:url]; + [mediaList addObject:url]; + NSUInteger mediaListCount = mediaList.count; + if (mediaListCount > 30) { + for (NSUInteger x = 0; x < mediaListCount - 30; x++) { + [mutDict removeObjectForKey:[mediaList firstObject]]; + [mediaList removeObjectAtIndex:0]; + } + } + } else { + [mutDict removeObjectForKey:url]; + [mediaList removeObject:url]; + } + [defaults setObject:mutDict forKey:@"recentlyPlayedMedia"]; + [defaults setObject:mediaList forKey:@"recentlyPlayedMediaList"]; + [defaults synchronize]; +} + +@end diff --git a/modules/gui/macosx/windows/extensions/VLCExtensionsManager.m b/modules/gui/macosx/windows/extensions/VLCExtensionsManager.m index 5751c7261db0..d65cc44db838 100644 --- a/modules/gui/macosx/windows/extensions/VLCExtensionsManager.m +++ b/modules/gui/macosx/windows/extensions/VLCExtensionsManager.m @@ -239,6 +239,7 @@ - (void)inputChanged:(input_thread_t *)p_input { + // FIXME: this is never called! //This is unlikely, but can happen if no extension modules can be loaded. if (p_extensions_manager == NULL) return; diff --git a/po/POTFILES.in b/po/POTFILES.in index 33249fe09edd..46482564a18a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -452,8 +452,6 @@ modules/gui/macosx/coreinteraction/VLCClickerManager.h modules/gui/macosx/coreinteraction/VLCClickerManager.m modules/gui/macosx/coreinteraction/VLCCoreInteraction.h modules/gui/macosx/coreinteraction/VLCCoreInteraction.m -modules/gui/macosx/coreinteraction/VLCInputManager.h -modules/gui/macosx/coreinteraction/VLCInputManager.m modules/gui/macosx/coreinteraction/VLCVideoFilterHelper.h modules/gui/macosx/coreinteraction/VLCVideoFilterHelper.m modules/gui/macosx/extensions/NSScreen+VLCAdditions.h @@ -519,6 +517,8 @@ modules/gui/macosx/panels/dialogs/VLCResumeDialogController.h modules/gui/macosx/panels/dialogs/VLCResumeDialogController.m modules/gui/macosx/panels/dialogs/VLCTextfieldPanelController.h modules/gui/macosx/panels/dialogs/VLCTextfieldPanelController.m +modules/gui/macosx/playlist/VLCPlaybackContinuityController.h +modules/gui/macosx/playlist/VLCPlaybackContinuityController.m modules/gui/macosx/playlist/VLCPlaylistController.h modules/gui/macosx/playlist/VLCPlaylistController.m modules/gui/macosx/playlist/VLCPlaylistDataSource.h -- GitLab