From 8bfedfc21da43fe41476fbeb027b56d574237336 Mon Sep 17 00:00:00 2001 From: Paddy Xu Date: Sun, 4 Jun 2017 17:26:07 +0300 Subject: [PATCH] real async plugin loading --- QuickLook/BackgroundListener.cs | 4 +- QuickLook/MainWindowTransparent.xaml.cs | 40 ++++++-------- QuickLook/PluginManager.cs | 1 - QuickLook/ViewWindowManager.cs | 73 ++++++++++++------------- 4 files changed, 55 insertions(+), 63 deletions(-) diff --git a/QuickLook/BackgroundListener.cs b/QuickLook/BackgroundListener.cs index 9f6d03e..46d79dd 100644 --- a/QuickLook/BackgroundListener.cs +++ b/QuickLook/BackgroundListener.cs @@ -1,5 +1,6 @@ using System; using System.Windows.Forms; +using System.Windows.Threading; namespace QuickLook { @@ -25,7 +26,8 @@ namespace QuickLook if (e.Modifiers != Keys.None) return; - ViewWindowManager.GetInstance().InvokeRoutine(e); + Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => ViewWindowManager.GetInstance().InvokeRoutine(e)), + DispatcherPriority.ApplicationIdle); } private void InstallKeyHook(KeyEventHandler handler) diff --git a/QuickLook/MainWindowTransparent.xaml.cs b/QuickLook/MainWindowTransparent.xaml.cs index 7283a5e..f5aa3ac 100644 --- a/QuickLook/MainWindowTransparent.xaml.cs +++ b/QuickLook/MainWindowTransparent.xaml.cs @@ -16,9 +16,6 @@ namespace QuickLook /// public partial class MainWindowTransparent : Window { - private string _path = string.Empty; - private IViewer _plugin; - internal MainWindowTransparent() { // this object should be initialized before loading UI components, because many of which are binding to it. @@ -43,18 +40,21 @@ namespace QuickLook ViewWindowManager.GetInstance().RunAndClosePreview(); } + public string PreviewPath { get; private set; } + public IViewer Plugin { get; private set; } + public ContextObject ContextObject { get; private set; } internal void RunAndHide() { - if (string.IsNullOrEmpty(_path)) + if (string.IsNullOrEmpty(PreviewPath)) return; try { - Process.Start(new ProcessStartInfo(_path) + Process.Start(new ProcessStartInfo(PreviewPath) { - WorkingDirectory = Path.GetDirectoryName(_path) + WorkingDirectory = Path.GetDirectoryName(PreviewPath) }); } catch (Exception e) @@ -96,21 +96,21 @@ namespace QuickLook ContextObject.Reset(); - _plugin?.Cleanup(); - _plugin = null; + Plugin?.Cleanup(); + Plugin = null; ProcessHelper.PerformAggressiveGC(); } - internal void BeginShow(IViewer matchedPlugin, string path) + internal void BeginShow(IViewer matchedPlugin, string path, Action exceptionHandler) { - _path = path; - _plugin = matchedPlugin; + PreviewPath = path; + Plugin = matchedPlugin; ContextObject.ViewerWindow = this; // get window size before showing it - _plugin.Prepare(path, ContextObject); + Plugin.Prepare(path, ContextObject); SetOpenWithButtonAndPath(); @@ -129,31 +129,27 @@ namespace QuickLook //WindowHelper.SetActivate(new WindowInteropHelper(this), ContextObject.CanFocus); // load plugin, do not block UI - Exception thrown = null; Dispatcher.BeginInvoke(new Action(() => { try { - _plugin.View(path, ContextObject); + Plugin.View(path, ContextObject); } catch (Exception e) { - thrown = e; + exceptionHandler(ExceptionDispatchInfo.Capture(e)); } }), - DispatcherPriority.Render).Wait(); - - if (thrown != null) - ExceptionDispatchInfo.Capture(thrown).Throw(); + DispatcherPriority.Input); } private void SetOpenWithButtonAndPath() { - var isExe = FileHelper.GetAssocApplication(_path, out string appFriendlyName); + var isExe = FileHelper.GetAssocApplication(PreviewPath, out string appFriendlyName); buttonOpenWith.Content = isExe == null - ? Directory.Exists(_path) - ? $"Browse “{Path.GetFileName(_path)}”" + ? Directory.Exists(PreviewPath) + ? $"Browse “{Path.GetFileName(PreviewPath)}”" : "Open..." : isExe == true ? $"Run “{appFriendlyName}”" diff --git a/QuickLook/PluginManager.cs b/QuickLook/PluginManager.cs index 927be62..07d8fef 100644 --- a/QuickLook/PluginManager.cs +++ b/QuickLook/PluginManager.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; -using System.Threading.Tasks; using QuickLook.ExtensionMethods; using QuickLook.Plugin; using QuickLook.Plugin.InfoPanel; diff --git a/QuickLook/ViewWindowManager.cs b/QuickLook/ViewWindowManager.cs index 5a80e38..a94c9dc 100644 --- a/QuickLook/ViewWindowManager.cs +++ b/QuickLook/ViewWindowManager.cs @@ -4,6 +4,7 @@ using System.IO; using System.Runtime.ExceptionServices; using System.Windows; using System.Windows.Forms; +using System.Windows.Threading; using QuickLook.Helpers; using QuickLook.Plugin; @@ -123,8 +124,8 @@ namespace QuickLook private void SwitchPreviewRemoteInvoke(HeartbeatEventArgs e) { - // sleep for 1.5s - if (e.InvokeTick - _lastSwitchTick < 1.5 * TimeSpan.TicksPerSecond) + // sleep for 0.6s + if (e.InvokeTick - _lastSwitchTick < 0.6 * TimeSpan.TicksPerSecond) return; if (e.FocusedFile == _path) @@ -135,7 +136,7 @@ namespace QuickLook if (string.IsNullOrEmpty(e.FocusedFile)) return; - _currentMainWindow?.Dispatcher.Invoke(() => SwitchPreview()); + _currentMainWindow?.Dispatcher.BeginInvoke(new Action(SwitchPreview), DispatcherPriority.ApplicationIdle); } private void RunFocusMonitor() @@ -158,59 +159,53 @@ namespace QuickLook internal bool InvokeViewer(string path = null) { - if (path == null) - path = _path; + if (path != null) + _path = path; - if (string.IsNullOrEmpty(path)) + if (string.IsNullOrEmpty(_path)) return false; - if (!Directory.Exists(path) && !File.Exists(path)) + if (!Directory.Exists(_path) && !File.Exists(_path)) return false; RunFocusMonitor(); - var matchedPlugin = PluginManager.GetInstance().FindMatch(path); + var matchedPlugin = PluginManager.GetInstance().FindMatch(_path); - BeginShowNewWindow(matchedPlugin, path); + BeginShowNewWindow(matchedPlugin); return true; } - private void BeginShowNewWindow(IViewer matchedPlugin, string path) + private void BeginShowNewWindow(IViewer matchedPlugin) { - try - { - _currentMainWindow.UnloadPlugin(); + _currentMainWindow.UnloadPlugin(); - // switch window - var oldWindow = _currentMainWindow; - _currentMainWindow = matchedPlugin.AllowsTransparency - ? _viewWindowTransparentTransparent - : _viewWindowNoTransparent; - if (!ReferenceEquals(oldWindow, _currentMainWindow)) - oldWindow.BeginHide(); + // switch window + var oldWindow = _currentMainWindow; + _currentMainWindow = matchedPlugin.AllowsTransparency + ? _viewWindowTransparentTransparent + : _viewWindowNoTransparent; + if (!ReferenceEquals(oldWindow, _currentMainWindow)) + oldWindow.BeginHide(); - _currentMainWindow.BeginShow(matchedPlugin, path); - } - catch (Exception e) // if current plugin failed, switch to default one. - { - _currentMainWindow.BeginHide(); + _currentMainWindow.BeginShow(matchedPlugin, _path, CurrentPluginFailed); + } - TrayIconManager.GetInstance().ShowNotification("", $"Failed to preview {Path.GetFileName(path)}", true); + private void CurrentPluginFailed(ExceptionDispatchInfo e) + { + var plugin = _currentMainWindow.Plugin.GetType(); - Debug.WriteLine(e.ToString()); - Debug.WriteLine(e.StackTrace); + _currentMainWindow.BeginHide(); - if (matchedPlugin != PluginManager.GetInstance().DefaultPlugin) - { - matchedPlugin.Cleanup(); - matchedPlugin = PluginManager.GetInstance().DefaultPlugin; - BeginShowNewWindow(matchedPlugin, path); - } - else - { - ExceptionDispatchInfo.Capture(e).Throw(); - } - } + TrayIconManager.GetInstance().ShowNotification("", $"Failed to preview {Path.GetFileName(_path)}", true); + + Debug.WriteLine(e.ToString()); + Debug.WriteLine(e.SourceException.StackTrace); + + if (plugin != PluginManager.GetInstance().DefaultPlugin.GetType()) + BeginShowNewWindow(PluginManager.GetInstance().DefaultPlugin); + else + e.Throw(); } internal static ViewWindowManager GetInstance()