Zonble: Use fsStreamHelper to monitor data changes.
This commit is contained in:
parent
115f197b72
commit
541e96ab70
|
@ -128,13 +128,23 @@ struct VersionUpdateApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc(AppDelegate)
|
@objc(AppDelegate)
|
||||||
class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControllerDelegate {
|
class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControllerDelegate, FSEventStreamHelperDelegate {
|
||||||
|
func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event]) {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if Preferences.shouldAutoReloadUserDataFiles {
|
||||||
|
LanguageModelManager.loadUserPhrases()
|
||||||
|
LanguageModelManager.loadUserPhraseReplacement()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@IBOutlet weak var window: NSWindow?
|
@IBOutlet weak var window: NSWindow?
|
||||||
private var preferencesWindowController: PreferencesWindowController?
|
private var preferencesWindowController: PreferencesWindowController?
|
||||||
private var aboutWindowController: frmAboutWindow? // New About Window
|
private var aboutWindowController: frmAboutWindow? // New About Window
|
||||||
private var checkTask: URLSessionTask?
|
private var checkTask: URLSessionTask?
|
||||||
private var updateNextStepURL: URL?
|
private var updateNextStepURL: URL?
|
||||||
|
private var fsStreamHelper = FSEventStreamHelper(path: LanguageModelManager.dataFolderPath, queue: DispatchQueue(label: "User Phrases"))
|
||||||
|
|
||||||
// 補上 dealloc
|
// 補上 dealloc
|
||||||
deinit {
|
deinit {
|
||||||
|
@ -149,6 +159,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControlle
|
||||||
LanguageModelManager.loadCNSData()
|
LanguageModelManager.loadCNSData()
|
||||||
LanguageModelManager.loadUserPhrases()
|
LanguageModelManager.loadUserPhrases()
|
||||||
LanguageModelManager.loadUserPhraseReplacement()
|
LanguageModelManager.loadUserPhraseReplacement()
|
||||||
|
fsStreamHelper.delegate = self
|
||||||
|
_ = fsStreamHelper.start()
|
||||||
|
|
||||||
Preferences.setMissingDefaults()
|
Preferences.setMissingDefaults()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* FSEventStreamHelper.swift
|
||||||
|
*
|
||||||
|
* Copyright 2021-2022 vChewing Project (3-Clause BSD License).
|
||||||
|
* Derived from 2011-2022 OpenVanilla Project (MIT License).
|
||||||
|
* Some rights reserved. See "LICENSE.TXT" for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
public protocol FSEventStreamHelperDelegate: AnyObject {
|
||||||
|
func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event])
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FSEventStreamHelper : NSObject {
|
||||||
|
|
||||||
|
public struct Event {
|
||||||
|
var path: String
|
||||||
|
var flags: FSEventStreamEventFlags
|
||||||
|
var id: FSEventStreamEventId
|
||||||
|
}
|
||||||
|
|
||||||
|
public let path: String
|
||||||
|
public let dispatchQueue: DispatchQueue
|
||||||
|
public weak var delegate: FSEventStreamHelperDelegate?
|
||||||
|
|
||||||
|
@objc public init(path: String, queue: DispatchQueue) {
|
||||||
|
self.path = path
|
||||||
|
self.dispatchQueue = queue
|
||||||
|
}
|
||||||
|
|
||||||
|
private var stream: FSEventStreamRef? = nil
|
||||||
|
|
||||||
|
public func start() -> Bool {
|
||||||
|
if stream != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var context = FSEventStreamContext()
|
||||||
|
context.info = Unmanaged.passUnretained(self).toOpaque()
|
||||||
|
guard let stream = FSEventStreamCreate(nil, {
|
||||||
|
(stream, clientCallBackInfo, eventCount, eventPaths, eventFlags, eventIds) in
|
||||||
|
let helper = Unmanaged<FSEventStreamHelper>.fromOpaque(clientCallBackInfo!).takeUnretainedValue()
|
||||||
|
let pathsBase = eventPaths.assumingMemoryBound(to: UnsafePointer<CChar>.self)
|
||||||
|
let pathsPtr = UnsafeBufferPointer(start: pathsBase, count: eventCount)
|
||||||
|
let flagsPtr = UnsafeBufferPointer(start: eventFlags, count: eventCount)
|
||||||
|
let eventIDsPtr = UnsafeBufferPointer(start: eventIds, count: eventCount)
|
||||||
|
let events = (0..<eventCount).map {
|
||||||
|
FSEventStreamHelper.Event(path: String(cString: pathsPtr[$0]),
|
||||||
|
flags: flagsPtr[$0],
|
||||||
|
id: eventIDsPtr[$0] )
|
||||||
|
}
|
||||||
|
helper.delegate?.helper(helper, didReceive: events)
|
||||||
|
},
|
||||||
|
&context,
|
||||||
|
[path] as CFArray,
|
||||||
|
UInt64(kFSEventStreamEventIdSinceNow),
|
||||||
|
1.0,
|
||||||
|
FSEventStreamCreateFlags(kFSEventStreamCreateFlagNone)
|
||||||
|
) else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
FSEventStreamSetDispatchQueue(stream, dispatchQueue)
|
||||||
|
if !FSEventStreamStart(stream) {
|
||||||
|
FSEventStreamInvalidate(stream)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
self.stream = stream
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func stop() {
|
||||||
|
guard let stream = stream else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
FSEventStreamStop(stream)
|
||||||
|
FSEventStreamInvalidate(stream)
|
||||||
|
self.stream = nil
|
||||||
|
}
|
||||||
|
}
|
|
@ -192,11 +192,6 @@ static double FindHighestScore(const vector<NodeAnchor>& nodes, double epsilon)
|
||||||
NSString *basisKeyboardLayoutID = Preferences.basisKeyboardLayout;
|
NSString *basisKeyboardLayoutID = Preferences.basisKeyboardLayout;
|
||||||
[client overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID];
|
[client overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID];
|
||||||
|
|
||||||
// Load UserPhrases // 這裡今後需要改造成「驗證檔案指紋、根據驗證結果判定是否需要重新讀入」的形式。
|
|
||||||
if (Preferences.shouldAutoReloadUserDataFiles) {
|
|
||||||
[self reloadUserPhrases:(id)nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset the state
|
// reset the state
|
||||||
_currentDeferredClient = nil;
|
_currentDeferredClient = nil;
|
||||||
_currentCandidateClient = nil;
|
_currentCandidateClient = nil;
|
||||||
|
|
|
@ -181,7 +181,7 @@ static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewing
|
||||||
[writeFile writeData:data];
|
[writeFile writeData:data];
|
||||||
[writeFile closeFile];
|
[writeFile closeFile];
|
||||||
|
|
||||||
[self loadUserPhrases];
|
// [self loadUserPhrases]; // Not Needed since AppDelegate is handling this.
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,4 +17,5 @@
|
||||||
+ (void)loadCNSData;
|
+ (void)loadCNSData;
|
||||||
+ (void)loadUserPhrases;
|
+ (void)loadUserPhrases;
|
||||||
+ (void)loadUserPhraseReplacement;
|
+ (void)loadUserPhraseReplacement;
|
||||||
|
@property (class, readonly, nonatomic) NSString *dataFolderPath;
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
5B5F4F972792A4EA00922DC2 /* UserPhrasesLM.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B5F4F962792A4EA00922DC2 /* UserPhrasesLM.mm */; };
|
5B5F4F972792A4EA00922DC2 /* UserPhrasesLM.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B5F4F962792A4EA00922DC2 /* UserPhrasesLM.mm */; };
|
||||||
5B6797B52794822C004AC7CE /* PhraseReplacementMap.h in Sources */ = {isa = PBXBuildFile; fileRef = 5B6797B32794822C004AC7CE /* PhraseReplacementMap.h */; };
|
5B6797B52794822C004AC7CE /* PhraseReplacementMap.h in Sources */ = {isa = PBXBuildFile; fileRef = 5B6797B32794822C004AC7CE /* PhraseReplacementMap.h */; };
|
||||||
5B810D9F27A3A5E50032C1A9 /* LMConsolidator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B810D9D27A3A5E50032C1A9 /* LMConsolidator.mm */; };
|
5B810D9F27A3A5E50032C1A9 /* LMConsolidator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B810D9D27A3A5E50032C1A9 /* LMConsolidator.mm */; };
|
||||||
|
5B9DD0A927A7950D00ED335A /* FSEventStreamHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9DD0A827A7950D00ED335A /* FSEventStreamHelper.swift */; };
|
||||||
5BC2D2882793B434002C0BEC /* KeyValueBlobReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BC2D2862793B434002C0BEC /* KeyValueBlobReader.cpp */; };
|
5BC2D2882793B434002C0BEC /* KeyValueBlobReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BC2D2862793B434002C0BEC /* KeyValueBlobReader.cpp */; };
|
||||||
5BC2D28B2793B8FB002C0BEC /* EmacsKeyHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC2D28A2793B8FB002C0BEC /* EmacsKeyHelper.swift */; };
|
5BC2D28B2793B8FB002C0BEC /* EmacsKeyHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC2D28A2793B8FB002C0BEC /* EmacsKeyHelper.swift */; };
|
||||||
5BC2D28D2793B98F002C0BEC /* PreferencesModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC2D28C2793B98F002C0BEC /* PreferencesModule.swift */; };
|
5BC2D28D2793B98F002C0BEC /* PreferencesModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC2D28C2793B98F002C0BEC /* PreferencesModule.swift */; };
|
||||||
|
@ -124,6 +125,7 @@
|
||||||
5B9781D52763850700897999 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
5B9781D52763850700897999 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||||
5B9781D72763850700897999 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "Source/zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
5B9781D72763850700897999 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "Source/zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||||
5B9781D82763850700897999 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "Source/zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
5B9781D82763850700897999 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "Source/zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||||
|
5B9DD0A827A7950D00ED335A /* FSEventStreamHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FSEventStreamHelper.swift; sourceTree = "<group>"; };
|
||||||
5BA923AC2791B7C20001323A /* vChewingInstaller-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "vChewingInstaller-Bridging-Header.h"; sourceTree = "<group>"; };
|
5BA923AC2791B7C20001323A /* vChewingInstaller-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "vChewingInstaller-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
5BC2D2842793B434002C0BEC /* KeyValueBlobReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyValueBlobReader.h; sourceTree = "<group>"; };
|
5BC2D2842793B434002C0BEC /* KeyValueBlobReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyValueBlobReader.h; sourceTree = "<group>"; };
|
||||||
5BC2D2862793B434002C0BEC /* KeyValueBlobReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KeyValueBlobReader.cpp; sourceTree = "<group>"; };
|
5BC2D2862793B434002C0BEC /* KeyValueBlobReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KeyValueBlobReader.cpp; sourceTree = "<group>"; };
|
||||||
|
@ -264,6 +266,7 @@
|
||||||
5B6797B32794822C004AC7CE /* PhraseReplacementMap.h */,
|
5B6797B32794822C004AC7CE /* PhraseReplacementMap.h */,
|
||||||
5B810D9D27A3A5E50032C1A9 /* LMConsolidator.mm */,
|
5B810D9D27A3A5E50032C1A9 /* LMConsolidator.mm */,
|
||||||
5B810D9E27A3A5E50032C1A9 /* LMConsolidator.h */,
|
5B810D9E27A3A5E50032C1A9 /* LMConsolidator.h */,
|
||||||
|
5B9DD0A827A7950D00ED335A /* FSEventStreamHelper.swift */,
|
||||||
);
|
);
|
||||||
path = LanguageModel;
|
path = LanguageModel;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -714,6 +717,7 @@
|
||||||
5BD0D19A27943D390008F48E /* clsSFX.swift in Sources */,
|
5BD0D19A27943D390008F48E /* clsSFX.swift in Sources */,
|
||||||
5BDD25F9279D6D1200AA18F8 /* ioapi.m in Sources */,
|
5BDD25F9279D6D1200AA18F8 /* ioapi.m in Sources */,
|
||||||
5BE798A72793280C00337FF9 /* NotifierController.swift in Sources */,
|
5BE798A72793280C00337FF9 /* NotifierController.swift in Sources */,
|
||||||
|
5B9DD0A927A7950D00ED335A /* FSEventStreamHelper.swift in Sources */,
|
||||||
5B5F4F93279294A300922DC2 /* LanguageModelManager.mm in Sources */,
|
5B5F4F93279294A300922DC2 /* LanguageModelManager.mm in Sources */,
|
||||||
6A0D4ED215FC0D6400ABF4B3 /* InputMethodController.mm in Sources */,
|
6A0D4ED215FC0D6400ABF4B3 /* InputMethodController.mm in Sources */,
|
||||||
6A0D4ED315FC0D6400ABF4B3 /* main.swift in Sources */,
|
6A0D4ED315FC0D6400ABF4B3 /* main.swift in Sources */,
|
||||||
|
|
Loading…
Reference in New Issue